home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / fspdev / fspdevSrv.c < prev   
Encoding:
C/C++ Source or Header  |  1992-12-19  |  81.8 KB  |  2,507 lines

  1. /* 
  2.  * fspdevSrv.c --  
  3.  *
  4.  *    This file contains routines directly related to the request-response
  5.  *    protocol between the client and server processes.  Routines that
  6.  *    setup state, i.e. the SrvOpen, CltOpen, and migration routines,
  7.  *    are in fsPdevSetup.c.  Routines for the Control stream are
  8.  *    found in fsPdevControl.c
  9.  *
  10.  *    Operations on a pseudo-device are forwarded to a user-level server
  11.  *    process using a "request-response" protocol.
  12.  *    The server process declares a request buffer (and optionally a read
  13.  *    ahead buffer) in its address space.  The kernel puts requests, which
  14.  *    are generated when a client does an operation on the pseudo stream,
  15.  *    into the request buffer directly.  The server learns of new requests
  16.  *    by reading messages from the server stream that contain offsets within
  17.  *    the request buffer.  Write requests may not require a response from
  18.  *    the server.  Instead the kernel just puts the request into the buffer
  19.  *    and returns to the client.  This allows many requests to be buffered
  20.  *    before a context switch to the server process.  Similarly,
  21.  *    the server can put read data into the read ahead buffer for a pseudo
  22.  *    stream.  In this case a client's read will be satisfied from the
  23.  *    buffer and the server won't be contacted.
  24.  *
  25.  * Copyright 1987, 1988 Regents of the University of California
  26.  * Permission to use, copy, modify, and distribute this
  27.  * software and its documentation for any purpose and without
  28.  * fee is hereby granted, provided that the above copyright
  29.  * notice appear in all copies.  The University of California
  30.  * makes no representations about the suitability of this
  31.  * software for any purpose.  It is provided "as is" without
  32.  * express or implied warranty.
  33.  */
  34.  
  35. #ifndef lint
  36. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/fspdev/fspdevSrv.c,v 9.8 91/09/10 18:28:13 rab Exp $ SPRITE (Berkeley)";
  37. #endif not lint
  38.  
  39. #include <status.h>
  40. #include <sprite.h>
  41. #include <fs.h>
  42. #include <fsutil.h>
  43. #include <fsNameOps.h>
  44. #include <fsio.h>
  45. #include <fsconsist.h>
  46. #include <fsioLock.h>
  47. #include <fsdm.h>
  48. #include <fsStat.h>
  49. #include <fspdev.h>
  50. #include <proc.h>
  51. #include <rpc.h>
  52. #include <string.h>
  53. #include <fspdevInt.h>
  54. #include <dev/pfs.h>
  55.  
  56. /*
  57.  * Access to Fspdev_ServerIOHandle is monitored to serialize access to
  58.  * the request-response communication channel.
  59.  */
  60. #define LOCKPTR (&pdevHandlePtr->lock)
  61.  
  62. /*
  63.  * Flags for a pseudo device handle.
  64.  *    PDEV_SETUP        The server has set up state for the stream.
  65.  *    PDEV_BUSY        Set during request-response to ensure that
  66.  *                only one client process is using the stream.
  67.  *    PDEV_REPLY_READY    The server gave us a reply
  68.  *    PDEV_REPLY_FAILED    There was some problem (usually with copy in)
  69.  *                getting the reply from the server.
  70.  *    PDEV_SERVER_GONE    Set after the server closes its stream.
  71.  *    PDEV_READ_BUF_EMPTY    When set there is no data in the read ahead
  72.  *                buf.
  73.  *    PDEV_SERVER_KNOWS_IT    Set after the server has done a read and been
  74.  *                told that we too think the read ahead buffer
  75.  *                is empty.  This synchronization simplifies
  76.  *                things; there is no wrapping; there is no
  77.  *                confusion about full vs. empty.
  78.  *    PDEV_READ_PTRS_CHANGED    Set when we have used data from the read
  79.  *                ahead buffer.  This makes the server stream
  80.  *                selectable so it will find out about the
  81.  *                new pointers.
  82.  *    PDEV_WRITE_BEHIND    Write-behind is enabled for this stream.
  83.  *    PDEV_NO_BIG_WRITES    Causes writes larger than will fit into
  84.  *                the request buffer to fail.  This is to
  85.  *                support UDP socket semantics, sigh.
  86.  *    PDEV_NAMING        Set on the naming request-response channel.
  87.  *    PDEV_REQUEST_ABORTED    Set when the client aborts during a request-
  88.  *                response transaction so we ignore the next rply.
  89.  *    FS_USER_IN/OUT        These flags are borrowed from the stream flags
  90.  *                and indicate which buffers are in user space
  91.  */
  92. #define PDEV_SETUP        0x0001
  93. #define PDEV_BUSY        0x0002
  94. #define PDEV_REPLY_READY    0x0004
  95. #define PDEV_REPLY_FAILED    0x0008
  96. #define PDEV_SERVER_GONE    0x0010
  97. #define PDEV_READ_BUF_EMPTY    0x0020
  98. #define PDEV_SERVER_KNOWS_IT    0x0040
  99. #define PDEV_READ_PTRS_CHANGED    0x0080
  100. #define PDEV_WRITE_BEHIND    0x0100
  101. #define PDEV_NO_BIG_WRITES    0x0200
  102. #define PDEV_NAMING        0x0400
  103. #define PDEV_REQUEST_ABORTED    0x0800
  104. /*resrv FS_USER_IN        0x8000 */
  105. /*resrv FS_USER_OUT          0x800000 */
  106.  
  107. /*
  108.  * Forward declarations.
  109.  */
  110.  
  111. static ReturnStatus RequestResponse _ARGS_((
  112.     Fspdev_ServerIOHandle *pdevHandlePtr,
  113.     int hdrSize, register Pdev_RequestHdr *requestHdrPtr, int inputSize,
  114.     Address inputBuf, int replySize, Address replyBuf, 
  115.     Fs_IOReply *ioReplyPtr, Sync_RemoteWaiter *waitPtr));
  116. static void PdevClientWakeup _ARGS_((Fspdev_ServerIOHandle *pdevHandlePtr));
  117. static void PdevClientNotify _ARGS_((Fspdev_ServerIOHandle *pdevHandlePtr));
  118.  
  119. /*
  120.  *----------------------------------------------------------------------
  121.  *
  122.  * RequestResponse --
  123.  *
  124.  *    The general request-response protocol between a client's pseudo
  125.  *    stream and the server stream.  This passes a request to the server
  126.  *    that specifies the command and parameters, the size of the input data
  127.  *    and the max size of the reply.  Then, if a reply is needed, this blocks
  128.  *    the client until the server responds.
  129.  *
  130.  * Results:
  131.  *    An error code from the server, or from errors on the vm copies.
  132.  *
  133.  * Side effects:
  134.  *    The server process is locked while we copy the request into the
  135.  *    buffer in the server's address space.  The firstByte and lastByte
  136.  *    offsets into the pseudo stream request buffer are updated to
  137.  *    reflect the new request.  The corresponding server stream is
  138.  *    marked FS_READABLE.
  139.  *
  140.  *----------------------------------------------------------------------
  141.  */
  142.  
  143. INTERNAL static ReturnStatus
  144. RequestResponse(pdevHandlePtr, hdrSize, requestHdrPtr, inputSize, inputBuf,
  145.     replySize, replyBuf, ioReplyPtr, waitPtr)
  146.     register Fspdev_ServerIOHandle *pdevHandlePtr;    /* Caller should lock this
  147.                          * with the monitor lock. */
  148.     int            hdrSize;    /* Either sizeof(Pdev_Request) or
  149.                      * sizeof(Pfs_Request) */
  150.     register Pdev_RequestHdr *requestHdrPtr;    /* Caller fills in the
  151.                      * command and parameter parts. The
  152.                      * sizes are filled in here. */
  153.     int            inputSize;    /* Size of input buffer. */
  154.     Address        inputBuf;    /* Inputs of the remote command. */
  155.     int            replySize;    /* Size of output buffer.  0 means
  156.                      * no reply data expected.  If the
  157.                      * operation is PDEV_WRITE_ASYNC then no
  158.                      * reply is wanted and this is ignored*/
  159.     Address        replyBuf;    /* Results of the remote command. */
  160.     Fs_IOReply        *ioReplyPtr;    /* Amount transferred and signal to
  161.                      * return. (May be NIL if not needed.)*/
  162.     Sync_RemoteWaiter    *waitPtr;    /* Client process info for waiting.
  163.                      * Only needed for read & write. */
  164. {
  165.     register ReturnStatus  status;
  166.     Proc_ControlBlock       *serverProcPtr;   /* For VM copy operations */
  167.     register int       firstByte;         /* Offset into request buffer */
  168.     register int       lastByte;         /* Offset into request buffer */
  169.     int               room;         /* Room available in req. buf.*/
  170.     int               savedLastByte;    /* For error recovery */
  171.     int               savedFirstByte;   /*   ditto */
  172.  
  173.     if (ioReplyPtr != (Fs_IOReply *) NIL) {
  174.     ioReplyPtr->length = 0;
  175.     }
  176.  
  177.     if ((pdevHandlePtr == (Fspdev_ServerIOHandle *)NIL) ||
  178.     (pdevHandlePtr->flags & PDEV_SERVER_GONE)) {
  179.     return(DEV_OFFLINE);
  180.     } else if ((pdevHandlePtr->flags & PDEV_SETUP) == 0) {
  181.     panic( "RequestResponse: connection not set up\n");
  182.     }
  183.     /*
  184.      * See if we have to switch to a new request buffer.  This is needed
  185.      * to support UDP, which wants to set a maximum write size.  The max
  186.      * is implemented by letting the UDP server change the buffer size and
  187.      * setting the property that writes larger than the buffer fail.  We
  188.      * wait and switch after the request buffer empties.
  189.      */
  190.     firstByte = pdevHandlePtr->requestBuf.firstByte;
  191.     lastByte = pdevHandlePtr->requestBuf.lastByte;
  192.     if ((pdevHandlePtr->nextRequestBuffer != (Address)NIL) &&
  193.     ((firstByte > lastByte) || (firstByte == -1))) {
  194. #ifndef CLEAN
  195.     printf( "Switching to request buffer at 0x%x\n",
  196.                    pdevHandlePtr->nextRequestBuffer);
  197. #endif
  198.     pdevHandlePtr->requestBuf.data = pdevHandlePtr->nextRequestBuffer;
  199.     pdevHandlePtr->requestBuf.size = pdevHandlePtr->nextRequestBufSize;
  200.     pdevHandlePtr->nextRequestBuffer = (Address)NIL;
  201.     firstByte = -1;
  202.     }
  203.     /*
  204.      * FORMAT THE REQUEST HEADER.  Note that the complete message size is
  205.      * rounded up so subsequent messages start on word boundaries.
  206.      */
  207.     if (hdrSize == sizeof(Pdev_Request)) {
  208.     requestHdrPtr->magic = PDEV_REQUEST_MAGIC;
  209.     } else if (hdrSize == sizeof(Pfs_Request)) {
  210.     requestHdrPtr->magic = PFS_REQUEST_MAGIC;
  211.     } else {
  212.     panic( "RequestResponse: bad hdr size\n");
  213.     }
  214.     requestHdrPtr->requestSize = inputSize;
  215.     requestHdrPtr->replySize = replySize;
  216.     requestHdrPtr->messageSize = hdrSize +
  217.         ((inputSize + sizeof(int) - 1) / sizeof(int)) * sizeof(int);
  218.     if (pdevHandlePtr->requestBuf.size < requestHdrPtr->messageSize) {
  219.     printf("RequestResponse: request too large (%d > %d)\n",
  220.         requestHdrPtr->messageSize, pdevHandlePtr->requestBuf.size);
  221.     return(GEN_INVALID_ARG);
  222.     }
  223.  
  224.     PDEV_REQUEST_PRINT(&pdevHandlePtr->hdr.fileID, requestHdrPtr);
  225.     PDEV_REQUEST(&pdevHandlePtr->hdr.fileID, requestHdrPtr);
  226.  
  227.     /*
  228.      * PUT THE REQUEST INTO THE REQUEST BUFFER.
  229.      * We assume that our caller will not give us a request that can't all
  230.      * fit into the buffer.  However, if the buffer is not empty enough we
  231.      * wait for the server to catch up with us.  (Things could be optimized
  232.      * perhaps to wait for just enough room.  To be real clever you have
  233.      * to be careful when you reset the firstByte so that the server only
  234.      * notices after it has caught up with everything at the end of the
  235.      * buffer.  To keep things simple we just wait for the server to catch up
  236.      * completely if we can't fit this request in.)
  237.      */
  238.  
  239.     savedFirstByte = firstByte;
  240.     savedLastByte = lastByte;
  241.     if (firstByte > lastByte || firstByte == -1) {
  242.     /*
  243.      * Buffer has emptied.
  244.      */
  245.     firstByte = 0;
  246.     pdevHandlePtr->requestBuf.firstByte = firstByte;
  247.     lastByte = requestHdrPtr->messageSize - 1;
  248.     } else {
  249.     room = pdevHandlePtr->requestBuf.size - (lastByte + 1);
  250.     if (room < requestHdrPtr->messageSize) {
  251.         /*
  252.          * There is no room left at the end of the buffer.
  253.          * We wait and then put the request at the beginning.
  254.          */
  255.         while (pdevHandlePtr->requestBuf.firstByte <
  256.            pdevHandlePtr->requestBuf.lastByte) {
  257.         DBG_PRINT( (" (catch up) ") );
  258.         if (Sync_Wait(&pdevHandlePtr->caughtUp, TRUE)) {
  259.             status = GEN_ABORTED_BY_SIGNAL;
  260.             goto failure;
  261.         } else if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  262.             status = DEV_OFFLINE;
  263.             goto failure;
  264.         }
  265.         }
  266.         savedFirstByte = -1;
  267.         firstByte = 0;
  268.         pdevHandlePtr->requestBuf.firstByte = firstByte;
  269.         lastByte = requestHdrPtr->messageSize - 1;
  270.     } else {
  271.         /*
  272.          * Append the message to the other requests.
  273.          */
  274.         firstByte = lastByte + 1;
  275.         lastByte += requestHdrPtr->messageSize;
  276.     }
  277.     }
  278.     pdevHandlePtr->requestBuf.lastByte = lastByte;
  279.     DBG_PRINT( (" first %d last %d\n", firstByte, lastByte) );
  280.     pdevHandlePtr->operation = requestHdrPtr->operation;
  281.     if (pdevHandlePtr->operation == PFS_OPEN) {
  282.     /*
  283.      * We have to snarf up the hostID of the client doing the open
  284.      * so the new pseudo-device connection that may be set up as
  285.      * a side effect of PFS_OPEN is set up right.  The useFlags are
  286.      * needed to initialize the new client stream right.
  287.      */
  288.     register Pfs_Request *pfsRequestPtr = (Pfs_Request *)requestHdrPtr;
  289.     pdevHandlePtr->open.clientID = pfsRequestPtr->param.open.clientID;
  290.     pdevHandlePtr->open.useFlags = pfsRequestPtr->param.open.useFlags;
  291.     pdevHandlePtr->open.name = (char *)inputBuf;
  292.     }
  293.  
  294.     /*
  295.      * COPY REQUEST AND DATA.
  296.      * Copy the request and data out into the server's request buffer.
  297.      * We map to a proc table pointer for the server which has a side
  298.      * effect of locking down the server process so it can't disappear.
  299.      */
  300.  
  301.     serverProcPtr = Proc_LockPID(pdevHandlePtr->serverPID);
  302.     if (serverProcPtr == (Proc_ControlBlock *)NIL) {
  303.     status = DEV_OFFLINE;
  304.     goto failure;
  305.     }
  306.     status = Vm_CopyOutProc(hdrSize, (Address)requestHdrPtr, TRUE,
  307.                 serverProcPtr, (Address)
  308.                 &pdevHandlePtr->requestBuf.data[firstByte]);
  309.     if (status == SUCCESS) {
  310.     firstByte += hdrSize;
  311.     if (inputSize > 0) {
  312.         status = Vm_CopyOutProc(inputSize, inputBuf, 
  313.             (pdevHandlePtr->flags & FS_USER_IN) == 0, serverProcPtr,
  314.             (Address)&pdevHandlePtr->requestBuf.data[firstByte]);
  315.     }
  316.     }
  317.     Proc_Unlock(serverProcPtr);
  318.     if (status != SUCCESS) {
  319.     /*
  320.      * Either the message header or data couldn't get copied out.
  321.      * Reset the buffer pointers so the bad request isn't seen.
  322.      */
  323.     pdevHandlePtr->requestBuf.firstByte = savedFirstByte;
  324.     pdevHandlePtr->requestBuf.lastByte = savedLastByte;
  325.     goto failure;
  326.     }
  327.  
  328.     /*
  329.      * POKE THE SERVER so it can read the new pointer values.
  330.      * This is done here even if write-behind is enabled, even though our
  331.      * scheduler tends to wake up the server too soon.
  332.      * Although it is possible to put a notify in about 3 other places
  333.      * to catch cases where the client does a write-behind and then waits,
  334.      * not all clients are clever enough to use select.  That solution results
  335.      * in cases where a write can linger a long time in the request buffer.
  336.      * (cat /dev/syslog in a tx window is a good test case.)
  337.      */
  338.     Fsutil_FastWaitListNotify(&pdevHandlePtr->srvReadWaitList);
  339.  
  340.     if (pdevHandlePtr->operation != PDEV_WRITE_ASYNC) {
  341.     /*
  342.      * WAIT FOR A REPLY.
  343.      * We save the client's reply buffer address and processID in the
  344.      * stream state so the kernel can copy the reply directly from
  345.      * the server's address space to the client's when the server
  346.      * makes the IOC_PDEV_REPLY IOControl.
  347.      */
  348.  
  349.     pdevHandlePtr->replyBuf = replyBuf;
  350.     pdevHandlePtr->replySize = replySize;
  351.     pdevHandlePtr->clientPID = (Proc_GetEffectiveProc())->processID;
  352.     if (waitPtr != (Sync_RemoteWaiter *)NIL) {
  353.         pdevHandlePtr->clientWait = *waitPtr;
  354.     }
  355.     pdevHandlePtr->flags &= ~PDEV_REPLY_READY;
  356.     while ((pdevHandlePtr->flags & PDEV_REPLY_READY) == 0) {
  357.         if (Sync_Wait(&pdevHandlePtr->replyReady, TRUE)) {
  358.         if ((pdevHandlePtr->flags & PDEV_REPLY_READY) == 0) {
  359.             /*
  360.              * Client aborted before the server completed the request.
  361.              */
  362.             pdevHandlePtr->flags |= PDEV_REQUEST_ABORTED;
  363.         }
  364.         status = GEN_ABORTED_BY_SIGNAL;
  365.         goto failure;
  366.         } else if (pdevHandlePtr->flags &
  367.             (PDEV_REPLY_FAILED|PDEV_SERVER_GONE)) {
  368.         status = DEV_OFFLINE;
  369.         goto failure;
  370.         }
  371.     }
  372.     if (ioReplyPtr != (Fs_IOReply *) NIL) {
  373.         ioReplyPtr->length = pdevHandlePtr->reply.replySize;
  374.         ioReplyPtr->signal = pdevHandlePtr->reply.signal;
  375.         ioReplyPtr->code = pdevHandlePtr->reply.code;
  376.     }
  377.     } else {
  378.     pdevHandlePtr->reply.status = SUCCESS;
  379.     }
  380. failure:
  381.     pdevHandlePtr->replyBuf = (char *)NIL;
  382.     pdevHandlePtr->replySize = 0;
  383.     if (status == SUCCESS) {
  384.     status = pdevHandlePtr->reply.status;
  385.     }
  386.     return(status);
  387. }
  388.  
  389. /*
  390.  *----------------------------------------------------------------------
  391.  *
  392.  * FspdevServerStreamCreate --
  393.  *
  394.  *    Set up the stream state for a server's private channel to a client.
  395.  *    This creates a Fspdev_ServerIOHandle that has all the state for the
  396.  *    connection to the client.
  397.  *
  398.  * Results:
  399.  *    A pointer to the I/O handle created.  The handle is locked.
  400.  *    NIL is returned if a handle under the fileID already existed.
  401.  *
  402.  * Side effects:
  403.  *    The I/O handle for this connection between a client and the server
  404.  *    is installed and initialized.
  405.  *
  406.  *----------------------------------------------------------------------
  407.  */
  408.  
  409. Fspdev_ServerIOHandle *
  410. FspdevServerStreamCreate(ioFileIDPtr, name, naming)
  411.     Fs_FileID    *ioFileIDPtr;    /* File ID used for pseudo stream handle */
  412.     char    *name;        /* File name for error messages */
  413.     Boolean    naming;        /* True if this is a naming stream for a pfs */
  414. {
  415.     Fs_HandleHeader *hdrPtr;
  416.     register Fspdev_ServerIOHandle *pdevHandlePtr;
  417.     Boolean found;
  418.  
  419.     ioFileIDPtr->type = FSIO_SERVER_STREAM;
  420.     found = Fsutil_HandleInstall(ioFileIDPtr, sizeof(Fspdev_ServerIOHandle), name,
  421.                 FALSE, &hdrPtr);
  422.     pdevHandlePtr = (Fspdev_ServerIOHandle *)hdrPtr;
  423.     if (found) {
  424.     printf("ServerStreamCreate, found handle <%x,%x,%x>\n",
  425.           hdrPtr->fileID.serverID, hdrPtr->fileID.major,
  426.           hdrPtr->fileID.minor);
  427.     Fsutil_HandleRelease(pdevHandlePtr, TRUE);
  428.     return((Fspdev_ServerIOHandle *)NIL);
  429.     }
  430.     fs_Stats.object.pseudoStreams++;
  431.  
  432.     DBG_PRINT( ("ServerStreamOpen <%d,%x,%x>\n",
  433.         ioFileIDPtr->serverID, ioFileIDPtr->major, ioFileIDPtr->minor) );
  434.  
  435.     /*
  436.      * Initialize the state for the pseudo stream.  Remember that
  437.      * the request and read ahead buffers for the pseudo-stream are set up
  438.      * via IOControls by the server process later.  In the meantime we
  439.      * pretend the connection is busy to lock out requests.
  440.      */
  441.  
  442.     Sync_LockInitDynamic(&pdevHandlePtr->lock, "Fs:pdevLock");
  443.     pdevHandlePtr->flags = PDEV_BUSY;
  444.     if (naming) {
  445.     pdevHandlePtr->flags |= PDEV_NAMING;
  446.     }
  447.     pdevHandlePtr->selectBits = 0;
  448.     pdevHandlePtr->serverPID = (Proc_PID)NIL;
  449.     pdevHandlePtr->clientPID = (Proc_PID)NIL;
  450.  
  451.     pdevHandlePtr->requestBuf.data = (Address)NIL;
  452.     pdevHandlePtr->requestBuf.firstByte = -1;
  453.     pdevHandlePtr->requestBuf.lastByte = -1;
  454.     pdevHandlePtr->requestBuf.size = 0;
  455.  
  456.     pdevHandlePtr->nextRequestBuffer = (Address)NIL;
  457.  
  458.     pdevHandlePtr->readBuf.data = (Address)NIL;
  459.     pdevHandlePtr->readBuf.firstByte = -1;
  460.     pdevHandlePtr->readBuf.lastByte = -1;
  461.     pdevHandlePtr->readBuf.size = 0;
  462.  
  463.     pdevHandlePtr->operation = 0;
  464.     pdevHandlePtr->reply.status = NIL;
  465.     pdevHandlePtr->reply.replySize = 0;
  466.     pdevHandlePtr->replyBuf = (Address)NIL;
  467.  
  468.     pdevHandlePtr->setup.waiting = 0;
  469.     pdevHandlePtr->access.waiting = 0;
  470.     pdevHandlePtr->caughtUp.waiting = 0;
  471.     pdevHandlePtr->replyReady.waiting = 0;
  472.  
  473.     List_Init(&pdevHandlePtr->srvReadWaitList);
  474.  
  475.     pdevHandlePtr->clientWait.pid = NIL;
  476.     pdevHandlePtr->clientWait.hostID = NIL;
  477.     pdevHandlePtr->clientWait.waitToken = NIL;
  478.  
  479.     List_Init(&pdevHandlePtr->cltReadWaitList);
  480.     List_Init(&pdevHandlePtr->cltWriteWaitList);
  481.     List_Init(&pdevHandlePtr->cltExceptWaitList);
  482.  
  483.     pdevHandlePtr->ctrlHandlePtr = (Fspdev_ControlIOHandle *)NIL;
  484.  
  485.     pdevHandlePtr->userLevelID = *ioFileIDPtr;
  486.     pdevHandlePtr->open.clientID = NIL;
  487.     pdevHandlePtr->open.useFlags = 0;
  488.     pdevHandlePtr->open.name = (char *)NIL;
  489.  
  490.     return(pdevHandlePtr);
  491. }
  492.  
  493. /*
  494.  *----------------------------------------------------------------------
  495.  *
  496.  * FspdevServerStreamSelect --
  497.  *
  498.  *    Select a server's request/response stream.  This returns
  499.  *    FS_READABLE in the outFlags if there is data in the
  500.  *    server's request buffer.  The next read on the server stream
  501.  *    will return the current pointers into the buffer.
  502.  *
  503.  * Results:
  504.  *    SUCCESS
  505.  *
  506.  * Side effects:
  507.  *    None.
  508.  *
  509.  *----------------------------------------------------------------------
  510.  */
  511.  
  512. ReturnStatus
  513. FspdevServerStreamSelect(hdrPtr, waitPtr, readPtr, writePtr, exceptPtr)
  514.     Fs_HandleHeader    *hdrPtr;    /* Handle on device to select */
  515.     Sync_RemoteWaiter    *waitPtr;    /* Process info for remote waiting */
  516.     int         *readPtr;    /* Bit to clear if non-readable */
  517.     int         *writePtr;    /* Bit to clear if non-writeable */
  518.     int         *exceptPtr;    /* Bit to clear if non-exceptable */
  519. {
  520.     register Fspdev_ServerIOHandle    *pdevHandlePtr = (Fspdev_ServerIOHandle *)hdrPtr;
  521.  
  522.     LOCK_MONITOR;
  523.     if (*readPtr) {
  524.     if (((pdevHandlePtr->flags & PDEV_READ_PTRS_CHANGED) == 0) &&
  525.          ((pdevHandlePtr->requestBuf.firstByte == -1) ||
  526.           (pdevHandlePtr->requestBuf.firstByte >=
  527.           pdevHandlePtr->requestBuf.lastByte))) {
  528.         *readPtr = 0;
  529.         if (waitPtr != (Sync_RemoteWaiter *)NIL) {
  530.         Fsutil_FastWaitListInsert(&pdevHandlePtr->srvReadWaitList, waitPtr);
  531.         }
  532.     }
  533.     }
  534.     *writePtr = 0;
  535.     *exceptPtr = 0;
  536.     UNLOCK_MONITOR;
  537.     return(SUCCESS);
  538. }
  539.  
  540. /*
  541.  *----------------------------------------------------------------------
  542.  *
  543.  * FspdevServerStreamRead --
  544.  *
  545.  *    When the server reads on a server stream it is looking for a
  546.  *    message containing pointers into the request buffer that's
  547.  *    in its address spapce.  This routine returns those values.
  548.  *
  549.  * Results:
  550.  *    SUCCESS unless all clients have gone away.
  551.  *
  552.  * Side effects:
  553.  *    The buffer is filled a Pdev_BufPtrs structure.
  554.  *
  555.  *----------------------------------------------------------------------
  556.  */
  557. /*ARGSUSED*/
  558. ReturnStatus
  559. FspdevServerStreamRead(streamPtr, readPtr, waitPtr, replyPtr)
  560.     register Fs_Stream     *streamPtr;    /* Stream to read from. */
  561.     Fs_IOParam        *readPtr;    /* Read parameter block. */
  562.     Sync_RemoteWaiter    *waitPtr;    /* Process info for remote waiting */
  563.     Fs_IOReply        *replyPtr;    /* Signal to return, if any,
  564.                      * plus the amount read. */
  565. {
  566.     register Fspdev_ServerIOHandle *pdevHandlePtr =
  567.         (Fspdev_ServerIOHandle *)streamPtr->ioHandlePtr;
  568.     register ReturnStatus status;
  569.     Pdev_BufPtrs bufPtrs;
  570.     register int reqFirstByte, reqLastByte;
  571.  
  572.     LOCK_MONITOR;
  573.     /*
  574.      * The server stream is readable only if there are requests in the
  575.      * request buffer or if the read ahead buffers have changed since
  576.      * the last time the server did a read.
  577.      */
  578.     reqFirstByte = pdevHandlePtr->requestBuf.firstByte;
  579.     reqLastByte = pdevHandlePtr->requestBuf.lastByte;
  580.     if (reqFirstByte > pdevHandlePtr->requestBuf.size ||
  581.     reqLastByte > pdevHandlePtr->requestBuf.size) {
  582.     panic("PdevServerRead, pointers inconsistent\n");
  583.     UNLOCK_MONITOR;
  584.     return(GEN_INVALID_ARG);
  585.     }
  586.     if (((pdevHandlePtr->flags & PDEV_READ_PTRS_CHANGED) == 0) &&
  587.     ((reqFirstByte == -1) || (reqFirstByte > reqLastByte))) {
  588.     status = FS_WOULD_BLOCK;
  589.     replyPtr->length = 0;
  590.     Fsutil_FastWaitListInsert(&pdevHandlePtr->srvReadWaitList, waitPtr);
  591.     } else {
  592.     /*
  593.      * Copy the current pointers out to the server.  We include the
  594.      * server's address of the request buffer to support changing
  595.      * the request buffer after requests have started to flow.
  596.      */
  597.     bufPtrs.magic = PDEV_BUF_PTR_MAGIC;
  598.     bufPtrs.requestAddr = pdevHandlePtr->requestBuf.data;
  599.     if ((reqFirstByte == -1) || (reqFirstByte > reqLastByte)) {
  600.         /*
  601.          * Request buffer is empty.
  602.          */
  603.         bufPtrs.requestFirstByte = -1;
  604.         bufPtrs.requestLastByte = -1;
  605.     } else {
  606.         bufPtrs.requestFirstByte = reqFirstByte;
  607.         bufPtrs.requestLastByte = reqLastByte;
  608.     }
  609.  
  610.     /*
  611.      * The read ahead buffer is filled by the server until there is
  612.      * no room left.  Only after the kernel has emptied the
  613.      * read ahead buffer will the server start filling it again.
  614.      * We use the PDEV_SERVER_KNOWS_IT state bit to know when to
  615.      * expect new pointer values after the buffer empties.
  616.      */
  617.     if (pdevHandlePtr->flags & PDEV_READ_BUF_EMPTY) {
  618.         bufPtrs.readLastByte = -1;
  619.         bufPtrs.readFirstByte = -1;
  620.         pdevHandlePtr->flags |= PDEV_SERVER_KNOWS_IT;
  621.     } else {
  622.         bufPtrs.readFirstByte = pdevHandlePtr->readBuf.firstByte;
  623.         bufPtrs.readLastByte = pdevHandlePtr->readBuf.lastByte;
  624.     }
  625.     pdevHandlePtr->flags &= ~PDEV_READ_PTRS_CHANGED;
  626.     status = Vm_CopyOut(sizeof(Pdev_BufPtrs), (Address)&bufPtrs,
  627.                 readPtr->buffer);
  628.     replyPtr->length = sizeof(Pdev_BufPtrs);
  629.     DBG_PRINT( ("READ %x,%x req %d:%d read %d:%d\n",
  630.         pdevHandlePtr->hdr.fileID.major,
  631.         pdevHandlePtr->hdr.fileID.minor,
  632.         pdevHandlePtr->requestBuf.firstByte,
  633.         pdevHandlePtr->requestBuf.lastByte,
  634.         pdevHandlePtr->readBuf.firstByte,
  635.         pdevHandlePtr->readBuf.lastByte) );
  636.     }
  637.     UNLOCK_MONITOR;
  638.     return(status);
  639. }
  640.  
  641. /*
  642.  *----------------------------------------------------------------------
  643.  *
  644.  * FspdevServerStreamIOControl --
  645.  *
  646.  *    IOControls for the server's stream.  The server process uses this
  647.  *    to manipulate the request and read ahead buffers in its address
  648.  *    space.  It delcares them, and queries and sets pointers into them.
  649.  *    The server also replies to requests here, and notifies the kernel
  650.  *    when the pseudo-device is selectable.
  651.  *
  652.  * Results:
  653.  *    SUCCESS if all went well, otherwise a status from a Vm operation
  654.  *    or a consistency check.
  655.  *
  656.  * Side effects:
  657.  *    This is the main entry point for the server process to control
  658.  *    the pseudo-device connection to its clients.  The side effects
  659.  *    depend on the I/O control.
  660.  *
  661.  *----------------------------------------------------------------------
  662.  */
  663. /*ARGSUSED*/
  664. ENTRY ReturnStatus
  665. FspdevServerStreamIOControl(streamPtr, ioctlPtr, replyPtr)
  666.     Fs_Stream    *streamPtr;    /* Stream to server handle. */
  667.     Fs_IOCParam *ioctlPtr;    /* Standard I/O Control parameter block */
  668.     Fs_IOReply *replyPtr;    /* Output buffer length and signal to return */
  669. {
  670.     ReturnStatus    status = SUCCESS;
  671.     register Fspdev_ServerIOHandle    *pdevHandlePtr =
  672.         (Fspdev_ServerIOHandle *)streamPtr->ioHandlePtr;
  673.  
  674.     LOCK_MONITOR;
  675.  
  676.     if (ioctlPtr->format != mach_Format) {
  677.     panic("FsServerStreamIOControl: wrong format\n");
  678.     }
  679.     switch (ioctlPtr->command) {
  680.     case IOC_PDEV_SET_BUF: {
  681.         /*
  682.          * The server is declaring the buffer space used for requests
  683.          * and (optionally) for read ahead.
  684.          * To support UDP socket semantics, we let the server change
  685.          * the request buffer after things have already started up.
  686.          * (This is sort of a pain, as we have to let the current
  687.          * request buffer empty before switching.)
  688.          *
  689.          * Side effects:
  690.          *        Set the request, and optionally the read-ahead,
  691.          *        buffer pointers.  The setup condition is notified
  692.          *        to let the client's open transaction begin.
  693.          */
  694.         register Pdev_SetBufArgs *argPtr =
  695.             (Pdev_SetBufArgs *)ioctlPtr->inBuffer;
  696.         register int extraBytes;
  697.  
  698.         if (ioctlPtr->inBufSize != sizeof(Pdev_SetBufArgs)) {
  699.         status = GEN_INVALID_ARG;
  700.         } else if ((pdevHandlePtr->flags & PDEV_SETUP) == 0) {
  701.         /*
  702.          * Normal case, first time initialization.  Make sure the
  703.          * buffers are word aligned.
  704.          */
  705.         pdevHandlePtr->requestBuf.size = argPtr->requestBufSize;
  706.         pdevHandlePtr->requestBuf.data = argPtr->requestBufAddr;
  707.         extraBytes = (unsigned int)argPtr->requestBufAddr &
  708.                  (sizeof(int) - 1);
  709.         if (extraBytes) {
  710.             pdevHandlePtr->requestBuf.data += sizeof(int) - extraBytes;
  711.             pdevHandlePtr->requestBuf.size -= extraBytes;
  712.         }
  713.         pdevHandlePtr->requestBuf.firstByte = -1;
  714.         pdevHandlePtr->requestBuf.lastByte = -1;
  715.  
  716.         if (argPtr->readBufAddr == (Address)NIL ||
  717.             argPtr->readBufAddr == (Address)0) {
  718.             pdevHandlePtr->readBuf.data = (Address)NIL;
  719.             pdevHandlePtr->readBuf.size = 0;
  720.         } else {
  721.             pdevHandlePtr->readBuf.size = argPtr->readBufSize;
  722.             pdevHandlePtr->readBuf.data = argPtr->readBufAddr;
  723.             extraBytes = (unsigned int)argPtr->readBufAddr &
  724.                  (sizeof(int) - 1);
  725.             if (extraBytes) {
  726.             pdevHandlePtr->readBuf.data += sizeof(int) - extraBytes;
  727.             pdevHandlePtr->readBuf.size -= extraBytes;
  728.             }
  729.         }
  730.         pdevHandlePtr->readBuf.firstByte = -1;
  731.         pdevHandlePtr->readBuf.lastByte = -1;
  732.  
  733.         pdevHandlePtr->serverPID = ioctlPtr->procID;
  734.  
  735.         /*
  736.          * The state has been marked BUSY to simplify waiting in the
  737.          * routines that call RequestResponse, so we clear that bit.
  738.          */
  739.         pdevHandlePtr->flags &= ~PDEV_BUSY;
  740.         pdevHandlePtr->flags |= PDEV_SETUP|PDEV_READ_BUF_EMPTY|
  741.                          PDEV_SERVER_KNOWS_IT;
  742.         Sync_Broadcast(&pdevHandlePtr->access);
  743.         } else {
  744.         /*
  745.          * The server is changing request buffers.  We just remember
  746.          * the new buffer address and size here, and switch over
  747.          * in RequestResponse after the current request buffer empties.
  748.          */
  749.         pdevHandlePtr->nextRequestBuffer = argPtr->requestBufAddr;
  750.         pdevHandlePtr->nextRequestBufSize = argPtr->requestBufSize;
  751.         if (pdevHandlePtr->nextRequestBuffer == (Address)0) {
  752.             pdevHandlePtr->nextRequestBuffer = (Address)NIL;
  753.         }
  754.         }
  755.         break;
  756.     }
  757.     case IOC_PDEV_WRITE_BEHIND: {
  758.         /*
  759.          * Side effects:
  760.          *        Set/unset write-behind buffering in the request buffer.
  761.          */
  762.         register Boolean writeBehind;
  763.         if (ioctlPtr->inBufSize < sizeof(Boolean)) {
  764.         status = GEN_INVALID_ARG;
  765.         } else {
  766.         writeBehind = *(Boolean *)ioctlPtr->inBuffer;
  767.         if (writeBehind) {
  768.             pdevHandlePtr->flags |= PDEV_WRITE_BEHIND;
  769.         } else {
  770.             pdevHandlePtr->flags &= ~PDEV_WRITE_BEHIND;
  771.         }
  772.         }
  773.         break;
  774.     }
  775.     case IOC_PDEV_BIG_WRITES: {
  776.         /*
  777.          * Side effects:
  778.          *        Set/unset the client's ability to make large writes.
  779.          */
  780.         register Boolean allowLargeWrites;
  781.         if (ioctlPtr->inBufSize < sizeof(Boolean)) {
  782.         status = GEN_INVALID_ARG;
  783.         } else {
  784.         allowLargeWrites = *(Boolean *)ioctlPtr->inBuffer;
  785.         if (allowLargeWrites) {
  786.             pdevHandlePtr->flags &= ~PDEV_NO_BIG_WRITES;
  787.         } else {
  788.             pdevHandlePtr->flags |= PDEV_NO_BIG_WRITES;
  789.         }
  790.         }
  791.         break;
  792.     }
  793.     case IOC_PDEV_SET_PTRS: {
  794.         /*
  795.          * The server is telling us about new pointer values.  We only
  796.          * pay attention to the requestFirstByte and readLastByte as
  797.          * it is our job to modify the other pointers.
  798.          *
  799.          * Side effects:
  800.          *        Set requestBuf.firstByte and readBuf.lastByte if
  801.          *        the server gives us new values (not equal -1).
  802.          *        We notify waiting clients if the server has
  803.          *        added read-ahead data.
  804.          */
  805.         register Pdev_BufPtrs *argPtr = (Pdev_BufPtrs *)ioctlPtr->inBuffer;
  806.         if (ioctlPtr->inBufSize != sizeof(Pdev_BufPtrs)) {
  807.         status = GEN_INVALID_ARG;
  808.         } else {
  809.         /*
  810.          * Verify the request buffer pointer.  The server may just
  811.          * be telling us about read ahead data, in which case we
  812.          * shouldn't muck with the request pointers. Otherwise we
  813.          * update the request first byte to reflect the processing
  814.          * of some requests by the server.
  815.          */
  816.         DBG_PRINT( ("SET  %x,%x req %d:%d read %d:%d\n",
  817.             pdevHandlePtr->hdr.fileID.major,
  818.             pdevHandlePtr->hdr.fileID.minor,
  819.             argPtr->requestFirstByte, argPtr->requestLastByte,
  820.             argPtr->readFirstByte, argPtr->readLastByte) );
  821.         if (argPtr->requestFirstByte <=
  822.                     pdevHandlePtr->requestBuf.size &&
  823.             argPtr->requestFirstByte >= 0) {
  824.             pdevHandlePtr->requestBuf.firstByte =
  825.                argPtr->requestFirstByte;
  826.         }
  827.         Sync_Broadcast(&pdevHandlePtr->caughtUp);
  828.             if ((pdevHandlePtr->readBuf.data == (Address)NIL) ||
  829.             (argPtr->readLastByte < 0)) {
  830.             /*
  831.              * No read ahead info.
  832.              */
  833.             break;
  834.         }
  835.         if (argPtr->readLastByte > pdevHandlePtr->readBuf.size) {
  836.             printf("FspdevServerStreamIOControl: set bad readPtr\n");
  837.             status = GEN_INVALID_ARG;
  838.             break;
  839.         }
  840.         if ((pdevHandlePtr->flags & PDEV_READ_BUF_EMPTY) == 0) {
  841.             /*
  842.              * Non-empty buffer.  Break out if bad pointer, else
  843.              * fall through to code that updates the pointer.
  844.              */
  845.             if (argPtr->readLastByte <=
  846.             pdevHandlePtr->readBuf.lastByte) {
  847.                 break;    /* No new read ahead data */
  848.             }
  849.         } else if (pdevHandlePtr->flags & PDEV_SERVER_KNOWS_IT) {
  850.             /*
  851.              * Empty buffer and the server already knows this.
  852.              * We can safely reset firstByte to the beginning.
  853.              * The server should rely on this behavior.
  854.              */
  855.             if (argPtr->readLastByte >= 0) {
  856.             pdevHandlePtr->flags &= ~(PDEV_READ_BUF_EMPTY|
  857.                          PDEV_SERVER_KNOWS_IT);
  858.             pdevHandlePtr->readBuf.firstByte = 0;
  859.             } else {
  860.             break;    /* No new read ahead data */
  861.             }
  862.         } else {
  863.             /*
  864.              * We emptied the buffer, but the server added data
  865.              * before seeing it was empty.  Can't reset firstByte.
  866.              */
  867.             if (argPtr->readLastByte > 
  868.                 pdevHandlePtr->readBuf.lastByte) {
  869.             pdevHandlePtr->flags &= ~PDEV_READ_BUF_EMPTY;
  870.             } else {
  871.             break;    /* No new read ahead data */
  872.             }
  873.         }
  874.         /*
  875.          * We know here that the lastByte pointer indicates
  876.          * more data.  Otherwise we've broken out.
  877.          * Update select state and poke waiting readers.
  878.          */
  879.         pdevHandlePtr->readBuf.lastByte = argPtr->readLastByte;
  880.         pdevHandlePtr->selectBits |= FS_READABLE;
  881.         Fsutil_FastWaitListNotify(&pdevHandlePtr->cltReadWaitList);
  882.         }
  883.         break;
  884.     }
  885.     case IOC_PDEV_SMALL_REPLY:
  886.     case IOC_PDEV_REPLY: {
  887.         /*
  888.          * The server is replying to a request.
  889.          *
  890.          * Side effects:
  891.          *        Copy the reply from the server to the client.
  892.          *        Put the client on wait lists, if appropriate.
  893.          *        Notify the replyReady condition, and lastly
  894.          *        notify waiting clients about new select state.
  895.          */
  896.         register Pdev_Reply *srvReplyPtr = (Pdev_Reply *)ioctlPtr->inBuffer;
  897.  
  898.         if (ioctlPtr->inBufSize < sizeof(Pdev_Reply)) {
  899.         /*
  900.          * inBuffer must be at least as big as Pdev_Reply.
  901.          * It will be larger during PDEV_SMALL_REPLY which
  902.          * includes a small amount of embedded data.
  903.          */
  904.         status = FS_INVALID_ARG;
  905.         pdevHandlePtr->flags |= PDEV_REPLY_READY|PDEV_REPLY_FAILED;
  906.         } else if (pdevHandlePtr->flags & PDEV_REQUEST_ABORTED) {
  907.         /*
  908.          * Client aborted the request from its end.
  909.          * Do nothing but grab the select bits.
  910.          */
  911.         pdevHandlePtr->flags &= ~PDEV_REQUEST_ABORTED;
  912.         pdevHandlePtr->selectBits = srvReplyPtr->selectBits;
  913.         } else {
  914.         /*
  915.          * Copy current reply in to pdev state.
  916.          */
  917.         pdevHandlePtr->reply = *srvReplyPtr;
  918.         if (srvReplyPtr->replySize > 0) {
  919.             register Proc_ControlBlock *clientProcPtr;
  920.             if (pdevHandlePtr->replyBuf == (char *)NIL) {
  921.             printf("PdevReply: unwanted reply data <%s>\n",
  922.                 Fsutil_HandleName(pdevHandlePtr));
  923.             goto noReplyData;
  924.             }
  925.             if (srvReplyPtr->replySize > pdevHandlePtr->replySize) {
  926.             printf("PdevReply: extra reply data (%d > %d) <%s>\n",
  927.                 srvReplyPtr->replySize, pdevHandlePtr->replySize,
  928.                 Fsutil_HandleName(pdevHandlePtr));
  929.             srvReplyPtr->replySize = pdevHandlePtr->replySize;
  930.             }
  931.             /*
  932.              * Copy the reply into the waiting buffers.
  933.              */
  934.             if ((ioctlPtr->command == IOC_PDEV_SMALL_REPLY) &&
  935.             ((srvReplyPtr->replySize > PDEV_SMALL_DATA_LIMIT) ||
  936.              (ioctlPtr->inBufSize <
  937.                  sizeof(Pdev_Reply) + srvReplyPtr->replySize))){
  938.             status = GEN_INVALID_ARG;
  939.             } else {
  940.             if ((pdevHandlePtr->flags & FS_USER_OUT) == 0) {
  941.                 /*
  942.                  * Reply buffer in the kernel.
  943.                  */
  944.                 if (ioctlPtr->command == IOC_PDEV_SMALL_REPLY) {
  945.                 bcopy(((Pdev_ReplyData *)srvReplyPtr)->data,
  946.                     pdevHandlePtr->replyBuf,
  947.                     srvReplyPtr->replySize);
  948.                 } else {
  949.                 status = Vm_CopyIn(srvReplyPtr->replySize,
  950.                            srvReplyPtr->replyBuf,
  951.                            pdevHandlePtr->replyBuf);
  952.                 }
  953.             } else {
  954.                 clientProcPtr = Proc_LockPID(pdevHandlePtr->clientPID);
  955.                 /*
  956.                  * Reply buffer in the client's address space.
  957.                  * Do a cross-address-space copy.
  958.                  */
  959.                 if (clientProcPtr == (Proc_ControlBlock *)NIL) {
  960.                 status = FS_BROKEN_PIPE;
  961.                 } else {
  962.                 if (ioctlPtr->command == IOC_PDEV_SMALL_REPLY) {
  963.                     status =
  964.                     Vm_CopyOutProc(srvReplyPtr->replySize,
  965.                     ((Pdev_ReplyData *)srvReplyPtr)->data,
  966.                     TRUE, clientProcPtr,
  967.                     pdevHandlePtr->replyBuf);
  968.                 } else {
  969.                     status =
  970.                     Vm_CopyOutProc(srvReplyPtr->replySize,
  971.                     srvReplyPtr->replyBuf, FALSE,
  972.                     clientProcPtr, pdevHandlePtr->replyBuf);
  973.                 }
  974.                 Proc_Unlock(clientProcPtr);
  975.                 }
  976.             }
  977.             }
  978.             if (status != SUCCESS) {
  979.             pdevHandlePtr->flags |= PDEV_REPLY_FAILED;
  980.             }
  981.         }
  982. noReplyData:
  983.         PDEV_REPLY(&pdevHandlePtr->hdr.fileID, srvReplyPtr);
  984.         if (srvReplyPtr->status == FS_WOULD_BLOCK) {
  985.             /*
  986.              * Put the client process on the appropriate wait list.
  987.              */
  988.             if (pdevHandlePtr->operation == PDEV_READ) {
  989.             Fsutil_FastWaitListInsert(&pdevHandlePtr->cltReadWaitList,
  990.                          &pdevHandlePtr->clientWait);
  991.             } else if (pdevHandlePtr->operation == PDEV_WRITE) {
  992.             Fsutil_FastWaitListInsert(&pdevHandlePtr->cltWriteWaitList,
  993.                          &pdevHandlePtr->clientWait);
  994.             }
  995.         }
  996.         pdevHandlePtr->flags |= PDEV_REPLY_READY;
  997.         pdevHandlePtr->selectBits = srvReplyPtr->selectBits;
  998.         }
  999.         Sync_Broadcast(&pdevHandlePtr->replyReady);
  1000.         PdevClientNotify(pdevHandlePtr);
  1001.         break;
  1002.     }
  1003.     case IOC_PDEV_READY:
  1004.         /*
  1005.          * Master has made the device ready.  The inBuffer contains
  1006.          * new select bits.
  1007.          *
  1008.          * Side effects:
  1009.          *        Notify waiting clients.
  1010.          */
  1011.  
  1012.         if (ioctlPtr->inBufSize != sizeof(int)) {
  1013.         status = FS_INVALID_ARG;
  1014.         } else {
  1015.         /*
  1016.          * Update the select state of the pseudo-device and
  1017.          * wake up any clients waiting on their pseudo-stream.
  1018.          */
  1019.         pdevHandlePtr->selectBits = *(int *)ioctlPtr->inBuffer;
  1020.         PdevClientNotify(pdevHandlePtr);
  1021.         }
  1022.         break;
  1023.     case IOC_PDEV_SIGNAL_OWNER: {
  1024.         /*
  1025.          * The server wants to signal the process (group) that owns
  1026.          * the device.  This is used, for example, to implement processing
  1027.          * of interrupt characters by the TTY driver.
  1028.          */
  1029.         status = FspdevSignalOwner(pdevHandlePtr->ctrlHandlePtr, ioctlPtr);
  1030.         break;
  1031.     }
  1032.     case IOC_PFS_OPEN: {
  1033.         /*
  1034.          * A pseudo-filesystem server is replying to an open request by
  1035.          * asking us to open a pseudo-device connection to the client.
  1036.          * It gives us a Fs_FileID for its own identification of the
  1037.          * connection.  The connection is set up here. A user-level
  1038.          * streamID is generated for the server process and returned.
  1039.          * To finish up, we set up the Fs_OpenResults that the waiting
  1040.          * client has to RequestResponse.  This includes a fileID so
  1041.          * the client process can fetch its half of the connection.
  1042.          */
  1043.         int newStreamID;            /* For the server */
  1044.         Fs_OpenResults openResults;        /* For the client */
  1045.  
  1046.         if (ioctlPtr->inBufSize < sizeof(Fs_FileID) ||
  1047.         ioctlPtr->outBufSize < sizeof(int)) {
  1048.         status = GEN_INVALID_ARG;
  1049.         } else if (pdevHandlePtr->flags & PDEV_REQUEST_ABORTED) {
  1050.         pdevHandlePtr->flags &= ~PDEV_REQUEST_ABORTED;
  1051.         PdevClientNotify(pdevHandlePtr);
  1052.         break;
  1053.         } else {
  1054.         newStreamID = FspdevPfsOpenConnection(pdevHandlePtr,
  1055.                 (Fs_FileID *)ioctlPtr->inBuffer, &openResults);
  1056.         if (ioctlPtr->flags & FS_USER_OUT) {
  1057.             Vm_CopyOut(sizeof(int), (Address)&newStreamID,
  1058.                 ioctlPtr->outBuffer);
  1059.         } else {
  1060.             *(int *)ioctlPtr->outBuffer = newStreamID;
  1061.         }
  1062.         if (newStreamID < 0) {
  1063.             status = FAILURE;
  1064.         } else {
  1065.             /*
  1066.              * Here we copy the openResults to the waiting processes
  1067.              * kernel stack (it's waiting in FspdevPfsOpen on this
  1068.              * same host.)
  1069.              */
  1070.             register Fs_OpenResults *openResultsPtr =
  1071.                 (Fs_OpenResults *)pdevHandlePtr->replyBuf;
  1072.             *openResultsPtr = openResults;
  1073.         }
  1074.         }
  1075.         if (status != SUCCESS) {
  1076.         pdevHandlePtr->flags |= PDEV_REPLY_FAILED;
  1077.         pdevHandlePtr->reply.replySize = 0;
  1078.         } else {
  1079.         pdevHandlePtr->reply.replySize = sizeof(Fs_OpenResults);
  1080.         }
  1081.         pdevHandlePtr->reply.status = status;
  1082.         pdevHandlePtr->flags |= PDEV_REPLY_READY;
  1083.         Sync_Broadcast(&pdevHandlePtr->replyReady);
  1084.         PdevClientNotify(pdevHandlePtr);
  1085.         break;
  1086.     }
  1087.     case IOC_PFS_SET_ID: {
  1088.         /*
  1089.          * A pseudo-filesystem server is setting its own notion of the
  1090.          * fileID associated with a request-response stream.
  1091.          */
  1092.         register Fs_FileID *fileIDPtr;
  1093.  
  1094.         if (ioctlPtr->inBufSize < sizeof(Fs_FileID)) {
  1095.         status = FS_INVALID_ARG;
  1096.         } else {
  1097.         fileIDPtr = (Fs_FileID *)ioctlPtr->inBuffer;
  1098.         pdevHandlePtr->userLevelID = *fileIDPtr;
  1099.         }
  1100.         break;
  1101.     }
  1102.     case IOC_PFS_PASS_STREAM: {
  1103.         /*
  1104.          * A pseudo-filesystem server is replying to an open request by
  1105.          * asking us to pass one of its open streams to the client.
  1106.          */
  1107.         register int passedStreamID;    /* From the server */
  1108.         Fs_OpenResults openResults;        /* For the client */
  1109.         Address encapStream;        /* packaged stream */
  1110.         int encapSize;            /* size of package */
  1111.         register Proc_ControlBlock *procPtr;
  1112.         register Fs_OpenResults *openResultsPtr;
  1113.  
  1114.         if (ioctlPtr->inBufSize < sizeof(int)) {
  1115.         status = GEN_INVALID_ARG;
  1116.         } else if (pdevHandlePtr->flags & PDEV_REQUEST_ABORTED) {
  1117.         pdevHandlePtr->flags &= ~PDEV_REQUEST_ABORTED;
  1118.         PdevClientNotify(pdevHandlePtr);
  1119.         break;
  1120.         } else {
  1121.         passedStreamID = *(int *)ioctlPtr->inBuffer;
  1122.         procPtr = Proc_GetEffectiveProc();
  1123.         status = Fs_GetStreamPtr(procPtr, passedStreamID, &streamPtr);
  1124.         if (status == SUCCESS) {
  1125.             encapSize = Fs_GetEncapSize();
  1126.             encapStream = (Address)malloc(encapSize);
  1127.             status = Fsio_EncapStream(streamPtr, encapStream);
  1128.             if (status == SUCCESS) {
  1129.             /*
  1130.              * Set up open results so Fs_Open will call a cltOpen
  1131.              * routine that will unpackage the encapsulated stream.
  1132.              */
  1133.             bzero((char *)&openResults, sizeof(Fs_OpenResults));
  1134.             openResults.ioFileID.type = FSIO_PASSING_STREAM;
  1135.             openResults.dataSize = encapSize;
  1136.             openResults.streamData = (ClientData)encapStream;
  1137.  
  1138.             openResultsPtr =
  1139.                 (Fs_OpenResults *)pdevHandlePtr->replyBuf;
  1140.             *openResultsPtr = openResults;
  1141.             }
  1142.         }
  1143.         }
  1144.         if (status != SUCCESS) {
  1145.         pdevHandlePtr->flags |= PDEV_REPLY_FAILED;
  1146.         pdevHandlePtr->reply.replySize = 0;
  1147.         } else {
  1148.         pdevHandlePtr->reply.replySize = sizeof(Fs_OpenResults);
  1149.         }
  1150.         pdevHandlePtr->reply.status = status;
  1151.         pdevHandlePtr->flags |= PDEV_REPLY_READY;
  1152.         Sync_Broadcast(&pdevHandlePtr->replyReady);
  1153.         PdevClientNotify(pdevHandlePtr);
  1154.         break;
  1155.     }
  1156.     case IOC_REPOSITION:
  1157.         status = GEN_INVALID_ARG;
  1158.         break;
  1159.     case IOC_GET_FLAGS:
  1160.     case IOC_SET_FLAGS:
  1161.     case IOC_SET_BITS:
  1162.     case IOC_CLEAR_BITS:
  1163.         /*
  1164.          * There are no server stream specific flags.
  1165.          */
  1166.         break;
  1167.     case IOC_TRUNCATE:
  1168.     case IOC_LOCK:
  1169.     case IOC_UNLOCK:
  1170.     case IOC_MAP:
  1171.         status = FS_INVALID_ARG;
  1172.         break;
  1173.     case IOC_GET_OWNER:
  1174.     case IOC_SET_OWNER:
  1175.         status = GEN_NOT_IMPLEMENTED;
  1176.         break;
  1177.     case IOC_NUM_READABLE: {
  1178.         /*
  1179.          * The server stream is readable only if there are requests in the
  1180.          * request buffer or if the read ahead buffers have changed since
  1181.          * the last time the server did a read.
  1182.          *
  1183.          * Side effects:
  1184.          *        None.
  1185.          */
  1186.         register int reqFirstByte, reqLastByte;
  1187.         register int numReadable;
  1188.  
  1189.         reqFirstByte = pdevHandlePtr->requestBuf.firstByte;
  1190.         reqLastByte = pdevHandlePtr->requestBuf.lastByte;
  1191.         if (((pdevHandlePtr->flags & PDEV_READ_PTRS_CHANGED) == 0) &&
  1192.         ((reqFirstByte == -1) || (reqFirstByte > reqLastByte))) {
  1193.         numReadable = 0;
  1194.         } else {
  1195.         numReadable = sizeof(Pdev_BufPtrs);
  1196.         }
  1197.         if (ioctlPtr->outBuffer == (Address)NIL ||
  1198.         ioctlPtr->outBufSize < sizeof(int)) {
  1199.         status = GEN_INVALID_ARG;
  1200.         } else {
  1201.         *(int *)ioctlPtr->outBuffer = numReadable;
  1202.         status = SUCCESS;
  1203.         }
  1204.         break;
  1205.     }
  1206.     case IOC_PREFIX: 
  1207.         status = SUCCESS;
  1208.         break;
  1209.     default:
  1210.         status = GEN_NOT_IMPLEMENTED;
  1211.         break;
  1212.     }
  1213.     UNLOCK_MONITOR;
  1214.     return(status);
  1215. }
  1216.  
  1217. /*
  1218.  *----------------------------------------------------------------------
  1219.  *
  1220.  * FspdevSignalOwner --
  1221.  *
  1222.  *    Send a signal to the owning process or family of a pseudo-device.
  1223.  *
  1224.  * Results:
  1225.  *    FS_INVALID_ARG if the input buffer isn't right.
  1226.  *
  1227.  * Side effects:
  1228.  *    Bypasses permissions and sends the signal.  Permissions have to
  1229.  *    be bypassed otherwise the pseudo-device server has to be setuid.
  1230.  *
  1231.  *----------------------------------------------------------------------
  1232.  */
  1233.  
  1234. ReturnStatus
  1235. FspdevSignalOwner(ctrlHandlePtr, ioctlPtr)
  1236.     Fspdev_ControlIOHandle *ctrlHandlePtr;
  1237.     Fs_IOCParam *ioctlPtr;
  1238. {
  1239.     register ReturnStatus status;
  1240.     register Pdev_Signal *sigPtr;
  1241.     register Ioc_Owner *ownerPtr = &ctrlHandlePtr->owner;
  1242.     register Proc_ControlBlock *procPtr;
  1243.  
  1244.     if (ownerPtr->procOrFamily == 0) {
  1245.     /*
  1246.      * No owner declared, this is a no-op.
  1247.      */
  1248.     status = SUCCESS;
  1249.     } else if (ioctlPtr->inBufSize != sizeof(Pdev_Signal)) {
  1250.     status = FS_INVALID_ARG;
  1251.     } else {
  1252.     register int savedEuid;
  1253.  
  1254.     sigPtr = (Pdev_Signal *)ioctlPtr->inBuffer;
  1255.     procPtr = Proc_GetEffectiveProc();
  1256.     savedEuid = procPtr->effectiveUserID;
  1257.     procPtr->effectiveUserID = 0;
  1258.     status = Sig_Send(sigPtr->signal, sigPtr->code, ownerPtr->id,
  1259.          (ownerPtr->procOrFamily == IOC_OWNER_FAMILY), (Address)0);
  1260.     procPtr->effectiveUserID = savedEuid;
  1261.     }
  1262.     return(status);
  1263. }
  1264.  
  1265.  
  1266. /*
  1267.  *----------------------------------------------------------------------
  1268.  *
  1269.  * FspdevServerStreamClose --
  1270.  *
  1271.  *    Clean up the state associated with a server stream.  This makes
  1272.  *    sure the client processes associated with the pseudo stream get
  1273.  *    poked, and it marks the pseudo stream's state as invalid so
  1274.  *    the clients will abort their current operations, if any.  The
  1275.  *    handle is 'removed' here, but it won't go away until the client
  1276.  *    side closes down and releases its reference to it.
  1277.  *
  1278.  * Results:
  1279.  *    SUCCESS.
  1280.  *
  1281.  * Side effects:
  1282.  *    Marks the pseudo stream state with PDEV_SERVER_GONE, notifies
  1283.  *    all conditions in pseudo stream state, wakes up all processes
  1284.  *    in any of the pseudo stream's wait lists, and then removes
  1285.  *    the handle from the hash table.
  1286.  *
  1287.  *----------------------------------------------------------------------
  1288.  */
  1289. /*ARGSUSED*/
  1290. ReturnStatus
  1291. FspdevServerStreamClose(streamPtr, clientID, procID, flags, size, data)
  1292.     Fs_Stream        *streamPtr;    /* Service stream to close */
  1293.     int            clientID;    /* HostID of client closing */
  1294.     Proc_PID        procID;        /* ID of closing process */
  1295.     int            flags;        /* Flags from the stream being closed */
  1296.     int            size;        /* Should be zero */
  1297.     ClientData        data;        /* IGNORED */
  1298. {
  1299.     register Fspdev_ServerIOHandle *pdevHandlePtr =
  1300.         (Fspdev_ServerIOHandle *)streamPtr->ioHandlePtr;
  1301.  
  1302.     DBG_PRINT( ("Server Closing pdev %x,%x\n", 
  1303.         pdevHandlePtr->hdr.fileID.major,
  1304.         pdevHandlePtr->hdr.fileID.minor) );
  1305.  
  1306.     PdevClientWakeup(pdevHandlePtr);
  1307.     if (pdevHandlePtr->flags & PDEV_NAMING) {
  1308.     /*
  1309.      * Clean up the prefix table entry associated with the pfs.
  1310.      */
  1311.     register Fspdev_ControlIOHandle *ctrlHandlePtr;
  1312.     Fs_Stream dummy;
  1313.  
  1314.     ctrlHandlePtr = pdevHandlePtr->ctrlHandlePtr;
  1315.     dummy.hdr.fileID.type = -1;
  1316.     dummy.ioHandlePtr = (Fs_HandleHeader *)ctrlHandlePtr;
  1317.     Fsutil_HandleLock(ctrlHandlePtr);
  1318.     Fsprefix_HandleClose(ctrlHandlePtr->prefixPtr, FSPREFIX_ANY);
  1319.     (void)FspdevControlClose(&dummy, clientID, procID, flags, 0, (ClientData)NIL);
  1320.     }
  1321.     Sync_LockClear(&pdevHandlePtr->lock);
  1322.     Fsutil_HandleRelease(pdevHandlePtr, TRUE);
  1323.     Fsutil_HandleRemove(pdevHandlePtr);    /* No need for scavenging */
  1324.     fs_Stats.object.pseudoStreams--;
  1325.     return(SUCCESS);
  1326. }
  1327.  
  1328. /*
  1329.  *----------------------------------------------------------------------
  1330.  *
  1331.  * PdevClientWakeup --
  1332.  *
  1333.  *    Called when the server's stream is closed.  This
  1334.  *    notifies the various conditions that the client might be
  1335.  *    waiting on and marks the pdev state as invalid so the
  1336.  *    client will bail out when it wakes up.
  1337.  *
  1338.  * Results:
  1339.  *    None.
  1340.  *
  1341.  * Side effects:
  1342.  *    Notifies condition variables and marks the pseudo stream as invalid.
  1343.  *
  1344.  *----------------------------------------------------------------------
  1345.  */
  1346.  
  1347. ENTRY static void
  1348. PdevClientWakeup(pdevHandlePtr)
  1349.     Fspdev_ServerIOHandle *pdevHandlePtr;    /* State for the pseudo stream */
  1350. {
  1351.     LOCK_MONITOR;
  1352.     /*
  1353.      * Set both "busy" and "server gone" because the standard preamble
  1354.      * for all client routines only checks against "server gone"
  1355.      * inside a while-not-busy loop.
  1356.      */
  1357.     pdevHandlePtr->flags |= (PDEV_SERVER_GONE|PDEV_REPLY_FAILED|PDEV_BUSY);
  1358.     Sync_Broadcast(&pdevHandlePtr->access);
  1359.     Sync_Broadcast(&pdevHandlePtr->caughtUp);
  1360.     Sync_Broadcast(&pdevHandlePtr->replyReady);
  1361.     Fsutil_FastWaitListNotify(&pdevHandlePtr->cltReadWaitList);
  1362.     Fsutil_FastWaitListNotify(&pdevHandlePtr->cltWriteWaitList);
  1363.     Fsutil_FastWaitListNotify(&pdevHandlePtr->cltExceptWaitList);
  1364.     Fsutil_WaitListDelete(&pdevHandlePtr->cltReadWaitList);
  1365.     Fsutil_WaitListDelete(&pdevHandlePtr->cltWriteWaitList);
  1366.     Fsutil_WaitListDelete(&pdevHandlePtr->cltExceptWaitList);
  1367.     Fsutil_WaitListDelete(&pdevHandlePtr->srvReadWaitList);
  1368.     UNLOCK_MONITOR;
  1369. }
  1370.  
  1371. /*
  1372.  *----------------------------------------------------------------------
  1373.  *
  1374.  * FspdevPdevServerOK --
  1375.  *
  1376.  *    Called from FspdevPfsExport to see if the server of a prefix still exists.
  1377.  *
  1378.  * Results:
  1379.  *    TRUE if the server process is still around.
  1380.  *
  1381.  * Side effects:
  1382.  *    None.
  1383.  *
  1384.  *----------------------------------------------------------------------
  1385.  */
  1386.  
  1387. ENTRY Boolean
  1388. FspdevPdevServerOK(pdevHandlePtr)
  1389.     Fspdev_ServerIOHandle *pdevHandlePtr;    /* State for the pseudo stream */
  1390. {
  1391.     register Boolean answer;
  1392.     LOCK_MONITOR;
  1393.     if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  1394.     answer = FALSE;
  1395.     } else {
  1396.     answer = TRUE;
  1397.     }
  1398.     UNLOCK_MONITOR;
  1399.     return(answer);
  1400. }
  1401.  
  1402.  
  1403. /*
  1404.  *----------------------------------------------------------------------
  1405.  *
  1406.  * FspdevPseudoStreamOpen --
  1407.  *
  1408.  *    Do the first request-response with a pseudo-device server to see if it
  1409.  *    will accept the open by the client.   This is used to tell
  1410.  *    the server something about the new stream it is getting,
  1411.  *    and to let it decide if it will accept the open.
  1412.  *
  1413.  * Results:
  1414.  *    The return status from the server's reply.  It can reject the open.
  1415.  *
  1416.  * Side effects:
  1417.  *    An PDEV_OPEN request-response is carried out.
  1418.  *
  1419.  *----------------------------------------------------------------------
  1420.  */
  1421.  
  1422. ENTRY ReturnStatus
  1423. FspdevPseudoStreamOpen(pdevHandlePtr, flags, clientID, procID, userID)
  1424.     register Fspdev_ServerIOHandle *pdevHandlePtr;    /* Pdev connection state */
  1425.     int        flags;        /* Open flags */
  1426.     int        clientID;    /* Host ID of the client */
  1427.     Proc_PID    procID;        /* Process ID of the client process */
  1428.     int        userID;        /* User ID of the client process */
  1429. {
  1430.     register ReturnStatus     status;
  1431.     Pdev_Request        request;
  1432.  
  1433.     LOCK_MONITOR;
  1434.  
  1435.     /*
  1436.      * Wait for the server to set up the request buffer.  The state starts
  1437.      * out PDEV_BUSY to eliminate an explicit check for PDEV_SETUP in all
  1438.      * the routines that call RequestResponse.  PDEV_BUSY is cleared after
  1439.      * the server initializes the request buffer with IOC_PDEV_SETUP.
  1440.      */
  1441.     while (pdevHandlePtr->flags & PDEV_BUSY) { 
  1442.     if ((pdevHandlePtr->flags & PDEV_SERVER_GONE) == 0) {
  1443.         (void)Sync_Wait(&pdevHandlePtr->access, FALSE);
  1444.     }
  1445.     if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  1446.         status = DEV_OFFLINE;
  1447.         goto exit;
  1448.     }
  1449.     }
  1450.     pdevHandlePtr->flags |= PDEV_BUSY;
  1451.  
  1452.     /*
  1453.      * Issue the first request to the server to see if it will accept us.
  1454.      */
  1455.  
  1456.     request.hdr.operation    = PDEV_OPEN;
  1457.     request.param.open.flags    = flags;
  1458.     request.param.open.pid    = procID;
  1459.     request.param.open.hostID    = clientID;
  1460.     request.param.open.uid    = userID;
  1461.  
  1462.     pdevHandlePtr->flags &= ~(FS_USER_IN|FS_USER_OUT);
  1463.     status = RequestResponse(pdevHandlePtr, sizeof(Pdev_Request), &request.hdr,
  1464.              0, (Address) NIL, 0, (Address) NIL, (Fs_IOReply *)NIL,
  1465.              (Sync_RemoteWaiter *)NIL);
  1466.     pdevHandlePtr->flags &= ~PDEV_BUSY;
  1467. exit:
  1468.     Sync_Broadcast(&pdevHandlePtr->access);
  1469.     UNLOCK_MONITOR;
  1470.     return(status);
  1471. }
  1472.  
  1473. /*
  1474.  *----------------------------------------------------------------------
  1475.  *
  1476.  * FspdevPseudoStreamLookup --
  1477.  *
  1478.  *    Do a lookup request-response to a pseudo-filesystem server over
  1479.  *    the naming request-response stream that is hooked to the prefix table.
  1480.  *    If a pathname redirection occurs this allocates a buffer for the
  1481.  *    returned pathname.  Otherwise this is a stub that passes its arguments
  1482.  *    up to the user level pseudo-filesystem server via request-response.
  1483.  *
  1484.  * Results:
  1485.  *    A status and some bundled results that aren't interpreted by us.
  1486.  *    If status is FS_REDIRECT then *newNameInfoPtrPtr has been allocated
  1487.  *    and contains the returned pathname.
  1488.  *
  1489.  * Side effects:
  1490.  *    The effect of the naming operation in the pseudo-filesystem is
  1491.  *    up to the pseudo-filesystem server.  Upon FS_REDIRECT this
  1492.  *    allocates the *newNameInfoPtrPtr buffer.
  1493.  *
  1494.  *----------------------------------------------------------------------
  1495.  */
  1496.  
  1497. ENTRY ReturnStatus
  1498. FspdevPseudoStreamLookup(pdevHandlePtr, requestPtr, argSize, argsPtr,
  1499.             resultsSizePtr, resultsPtr, newNameInfoPtrPtr)
  1500.     register Fspdev_ServerIOHandle *pdevHandlePtr;    /* Pdev connection state */
  1501.     Pfs_Request        *requestPtr;    /* Semi-initialized request header */
  1502.     int            argSize;    /* Size of argsPtr buffer */
  1503.     Address        argsPtr;    /* Ref. to bundled args, usually name */
  1504.     int            *resultsSizePtr;/* Out size of results */
  1505.     Address        resultsPtr;    /* Ref. to bundled results or 
  1506.                      * Fs_RedirectInfo */
  1507.     Fs_RedirectInfo    **newNameInfoPtrPtr;/* Set if server returns name */
  1508. {
  1509.     register ReturnStatus     status;
  1510.     Fs_RedirectInfo        redirectInfo;    /* This is a large buffer
  1511.                          * that is used for EITHER
  1512.                          * normal reply parameters
  1513.                          * or a redirected pathname */
  1514.     Fs_IOReply            ioReply;
  1515.  
  1516.     LOCK_MONITOR;
  1517.  
  1518.     *newNameInfoPtrPtr = (Fs_RedirectInfo *)NIL;
  1519.  
  1520.     while (pdevHandlePtr->flags & PDEV_BUSY) {
  1521.     if ((pdevHandlePtr->flags & PDEV_SERVER_GONE) == 0) {
  1522.         (void)Sync_Wait(&pdevHandlePtr->access, FALSE);
  1523.     }
  1524.     if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  1525.         status = FS_STALE_HANDLE;
  1526.         goto exit;
  1527.     }
  1528.     }
  1529.     pdevHandlePtr->flags |= PDEV_BUSY;
  1530.  
  1531.     pdevHandlePtr->flags &= ~(FS_USER_IN|FS_USER_OUT);
  1532.     status = RequestResponse(pdevHandlePtr, sizeof(Pfs_Request),
  1533.         &requestPtr->hdr, argSize, argsPtr, sizeof(Fs_RedirectInfo),
  1534.         (Address)&redirectInfo, &ioReply,
  1535.         (Sync_RemoteWaiter *)NIL);
  1536.     if (status == FS_LOOKUP_REDIRECT) {
  1537.     *newNameInfoPtrPtr = mnew(Fs_RedirectInfo);
  1538.     (*newNameInfoPtrPtr)->prefixLength = redirectInfo.prefixLength;
  1539.     (void)strcpy((*newNameInfoPtrPtr)->fileName, redirectInfo.fileName);
  1540.     } else {
  1541.     /*
  1542.      * Grab the result parameters.
  1543.      */
  1544.     *resultsSizePtr = ioReply.length;
  1545.     if (ioReply.length > 0) {
  1546.         bcopy((Address)&redirectInfo, resultsPtr, ioReply.length);
  1547.     }
  1548.     }
  1549.  
  1550.     if (status == DEV_OFFLINE) {
  1551.     /*
  1552.      * Return stale handle so remote clients know to nuke
  1553.      * their prefix table entry.
  1554.      */
  1555.     status = FS_STALE_HANDLE;
  1556.     }
  1557.     pdevHandlePtr->flags &= ~PDEV_BUSY;
  1558. exit:
  1559.     Sync_Broadcast(&pdevHandlePtr->access);
  1560.     UNLOCK_MONITOR;
  1561.     return(status);
  1562. }
  1563.  
  1564. /*
  1565.  *----------------------------------------------------------------------
  1566.  *
  1567.  * FspdevPseudoStream2Path --
  1568.  *
  1569.  *    Do a rename/link request-response to a pseudo-filesystem server over
  1570.  *    the naming request-response stream that is hooked to the prefix table.
  1571.  *    If a pathname redirection occurs this allocates a buffer for the
  1572.  *    returned pathname.  Otherwise this is a stub that passes its arguments
  1573.  *    up to the user level pseudo-filesystem server via request-response.
  1574.  *
  1575.  * Results:
  1576.  *    A status and some bundled results that aren't interpreted by us.
  1577.  *    If status is FS_REDIRECT then *newNameInfoPtrPtr has been allocated
  1578.  *    and contains the returned pathname.
  1579.  *
  1580.  * Side effects:
  1581.  *    The effect of the naming operation in the pseudo-filesystem is
  1582.  *    up to the pseudo-filesystem server.  Upon FS_REDIRECT this
  1583.  *    allocates the *newNameInfoPtrPtr buffer.
  1584.  *
  1585.  *----------------------------------------------------------------------
  1586.  */
  1587.  
  1588. ENTRY ReturnStatus
  1589. FspdevPseudoStream2Path(pdevHandlePtr, requestPtr, dataPtr, name1ErrorPtr,
  1590.             newNameInfoPtrPtr)
  1591.     register Fspdev_ServerIOHandle *pdevHandlePtr;    /* Pdev connection state */
  1592.     Pfs_Request        *requestPtr;    /* Semi-initialized request header */
  1593.     Fs_2PathData        *dataPtr;    /* 2 pathnames */
  1594.     Boolean        *name1ErrorPtr;    /* TRUE if error applies to first path*/
  1595.     Fs_RedirectInfo    **newNameInfoPtrPtr;/* Set if server returns name */
  1596. {
  1597.     register ReturnStatus     status;
  1598.     Fs_2PathRedirectInfo        redirectInfo;
  1599.  
  1600.     LOCK_MONITOR;
  1601.  
  1602.     while (pdevHandlePtr->flags & PDEV_BUSY) {
  1603.     if ((pdevHandlePtr->flags & PDEV_SERVER_GONE) == 0) {
  1604.         (void)Sync_Wait(&pdevHandlePtr->access, FALSE);
  1605.     }
  1606.     if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  1607.         status = FS_STALE_HANDLE;
  1608.         goto exit;
  1609.     }
  1610.     }
  1611.     pdevHandlePtr->flags |= PDEV_BUSY;
  1612.  
  1613.     pdevHandlePtr->flags &= ~(FS_USER_IN|FS_USER_OUT);
  1614.     status = RequestResponse(pdevHandlePtr, sizeof(Pfs_Request),
  1615.         &requestPtr->hdr, sizeof(Fs_2PathData), (Address)dataPtr,
  1616.         sizeof(Fs_2PathRedirectInfo), (Address)&redirectInfo,
  1617.         (Fs_IOReply *)NIL, (Sync_RemoteWaiter *)NIL);
  1618.     if (status == FS_LOOKUP_REDIRECT) {
  1619.     *newNameInfoPtrPtr = mnew(Fs_RedirectInfo);
  1620.     (*newNameInfoPtrPtr)->prefixLength = redirectInfo.prefixLength;
  1621.     (void)strcpy((*newNameInfoPtrPtr)->fileName, redirectInfo.fileName);
  1622.     }
  1623.     if (status != SUCCESS) {
  1624.     *name1ErrorPtr = redirectInfo.name1ErrorP;
  1625.     } else {
  1626.     *name1ErrorPtr = FALSE;
  1627.     }
  1628.  
  1629.     if (status == DEV_OFFLINE) {
  1630.     /*
  1631.      * Return stale handle so remote clients know to nuke
  1632.      * their prefix table entry.
  1633.      */
  1634.     status = FS_STALE_HANDLE;
  1635.     }
  1636.     pdevHandlePtr->flags &= ~PDEV_BUSY;
  1637. exit:
  1638.     Sync_Broadcast(&pdevHandlePtr->access);
  1639.     UNLOCK_MONITOR;
  1640.     return(status);
  1641. }
  1642.  
  1643. /*
  1644.  *----------------------------------------------------------------------
  1645.  *
  1646.  * FspdevPseudoGetAttr --
  1647.  *
  1648.  *    Called from Fs_GetAttributesID to get the attributes of a file
  1649.  *    in a pseudo-filesystem.  The stream's nameInfoPtr->fileID is
  1650.  *    set to the fileID of the pseudo-device connection to the server,
  1651.  *    and this ID is passed into us.  This does a PDEV_GET_ATTR request.
  1652.  *
  1653.  * Results:
  1654.  *    The attributes structure is passed back from the pfs server.
  1655.  *
  1656.  * Side effects:
  1657.  *    None.
  1658.  *
  1659.  *----------------------------------------------------------------------
  1660.  */
  1661. /*ARGSUSED*/
  1662. ReturnStatus
  1663. FspdevPseudoGetAttr(fileIDPtr, clientID, attrPtr)
  1664.     register Fs_FileID        *fileIDPtr;    /* Identfies pdev connection */
  1665.     int                clientID;    /* Host ID of process asking
  1666.                          * for the attributes */
  1667.     register Fs_Attributes    *attrPtr;    /* Return - the attributes */
  1668. {
  1669.     Fspdev_ClientIOHandle        *cltHandlePtr;
  1670.     Pdev_Request        request;
  1671.     register Fspdev_ServerIOHandle    *pdevHandlePtr;
  1672.     register ReturnStatus    status;
  1673.  
  1674.     cltHandlePtr = Fsutil_HandleFetchType(Fspdev_ClientIOHandle, fileIDPtr);
  1675.     if (cltHandlePtr == (Fspdev_ClientIOHandle *)NIL) {
  1676.     printf( "FspdevPseudoGetAttr, no %s handle <%d,%x,%x>\n",
  1677.         Fsutil_FileTypeToString(fileIDPtr->type), fileIDPtr->serverID,
  1678.         fileIDPtr->major, fileIDPtr->minor);
  1679.     return(FS_FILE_NOT_FOUND);
  1680.     }
  1681.     Fsutil_HandleRelease(cltHandlePtr, TRUE);
  1682.     pdevHandlePtr = cltHandlePtr->pdevHandlePtr;
  1683.     LOCK_MONITOR;
  1684.  
  1685.     while (pdevHandlePtr->flags & PDEV_BUSY) {
  1686.     if ((pdevHandlePtr->flags & PDEV_SERVER_GONE) == 0) {
  1687.         (void)Sync_Wait(&pdevHandlePtr->access, FALSE);
  1688.     }
  1689.     if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  1690.         status = DEV_OFFLINE;
  1691.         goto exit;
  1692.     }
  1693.     }
  1694.     pdevHandlePtr->flags |= PDEV_BUSY;
  1695.     pdevHandlePtr->flags &= ~(FS_USER_IN|FS_USER_OUT);
  1696.     request.hdr.operation = PDEV_GET_ATTR;
  1697.     status = RequestResponse(pdevHandlePtr, sizeof(Pdev_Request), &request.hdr,
  1698.             0, (Address) NIL,
  1699.             sizeof(Fs_Attributes), (Address)attrPtr,
  1700.             (Fs_IOReply *)NIL, (Sync_RemoteWaiter *)NIL);
  1701.     /*
  1702.      * Patch the serverID in the attributes so it matches the serverID
  1703.      * given in the prefix table.  This is needed to make getwd() work.
  1704.      */
  1705.     attrPtr->serverID = rpc_SpriteID;
  1706.  
  1707.     pdevHandlePtr->flags &= ~PDEV_BUSY;
  1708. exit:
  1709.     Sync_Broadcast(&pdevHandlePtr->access);
  1710.     UNLOCK_MONITOR;
  1711.     return(status);
  1712. }
  1713.  
  1714. /*
  1715.  *----------------------------------------------------------------------
  1716.  *
  1717.  * FspdevPseudoSetAttr --
  1718.  *
  1719.  *    Set the attributes of a file in a pseudo-filesystem.  We have the
  1720.  *    fileID of the request-response stream to the server.  This issues
  1721.  *    a PDEV_SET_ATTR request to the server that contains new attributes.
  1722.  *
  1723.  * Results:
  1724.  *    An error code.
  1725.  *
  1726.  * Side effects:
  1727.  *    None here.  The new attributes are shipped to the pfs server.
  1728.  *
  1729.  *----------------------------------------------------------------------
  1730.  */
  1731. /*ARGSUSED*/
  1732. ReturnStatus
  1733. FspdevPseudoSetAttr(fileIDPtr, attrPtr, idPtr, flags)
  1734.     register Fs_FileID        *fileIDPtr;    /* Identfies pdev connection */
  1735.     register Fs_Attributes    *attrPtr;    /* Return - the attributes */
  1736.     Fs_UserIDs            *idPtr;        /* Identfies user */
  1737.     int                flags;        /* Tells which attrs to set */
  1738. {
  1739.     Fspdev_ClientIOHandle        *cltHandlePtr;
  1740.     Pdev_Request        request;
  1741.     register Fspdev_ServerIOHandle    *pdevHandlePtr;
  1742.     register ReturnStatus    status;
  1743.  
  1744.     cltHandlePtr = Fsutil_HandleFetchType(Fspdev_ClientIOHandle, fileIDPtr);
  1745.     if (cltHandlePtr == (Fspdev_ClientIOHandle *)NIL) {
  1746.     printf( "FspdevPseudoSetAttr, no handle <%d,%d,%x,%x>\n",
  1747.         fileIDPtr->serverID, fileIDPtr->type,
  1748.         fileIDPtr->major, fileIDPtr->minor);
  1749.     return(FS_FILE_NOT_FOUND);
  1750.     }
  1751.     Fsutil_HandleRelease(cltHandlePtr, TRUE);
  1752.     pdevHandlePtr = cltHandlePtr->pdevHandlePtr;
  1753.     LOCK_MONITOR;
  1754.  
  1755.     while (pdevHandlePtr->flags & PDEV_BUSY) {
  1756.     if ((pdevHandlePtr->flags & PDEV_SERVER_GONE) == 0) {
  1757.         (void)Sync_Wait(&pdevHandlePtr->access, FALSE);
  1758.     }
  1759.     if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  1760.         status = DEV_OFFLINE;
  1761.         goto exit;
  1762.     }
  1763.     }
  1764.     pdevHandlePtr->flags |= PDEV_BUSY;
  1765.     pdevHandlePtr->flags &= ~(FS_USER_IN|FS_USER_OUT);
  1766.     request.hdr.operation = PDEV_SET_ATTR;
  1767.     request.param.setAttr.uid = idPtr->user;
  1768.     request.param.setAttr.flags = flags;
  1769.     status = RequestResponse(pdevHandlePtr, sizeof(Pdev_Request), &request.hdr,
  1770.             sizeof(Fs_Attributes), (Address)attrPtr,
  1771.             0, (Address) NIL,
  1772.             (Fs_IOReply *)NIL, (Sync_RemoteWaiter *)NIL);
  1773.     pdevHandlePtr->flags &= ~PDEV_BUSY;
  1774. exit:
  1775.     Sync_Broadcast(&pdevHandlePtr->access);
  1776.     UNLOCK_MONITOR;
  1777.     return(status);
  1778. }
  1779.  
  1780. /*
  1781.  *----------------------------------------------------------------------
  1782.  *
  1783.  * FspdevPseudoStreamGetIOAttr --
  1784.  *
  1785.  *    Called from Fs_GetAttrStream to get the I/O attributes of a
  1786.  *    pseudo-device.  The access and modify times of the pseudo-device
  1787.  *    are obtained from the internal pdev state.
  1788.  *
  1789.  * Results:
  1790.  *    SUCCESS.
  1791.  *
  1792.  * Side effects:
  1793.  *    None.
  1794.  *
  1795.  *----------------------------------------------------------------------
  1796.  */
  1797. ReturnStatus
  1798. FspdevPseudoStreamGetIOAttr(fileIDPtr, clientID, attrPtr)
  1799.     register Fs_FileID        *fileIDPtr;    /* Identfies pdev connection */
  1800.     int                clientID;    /* Host ID of process asking
  1801.                          * for the attributes */
  1802.     register Fs_Attributes    *attrPtr;    /* Return - the attributes */
  1803. {
  1804.     Fspdev_ClientIOHandle        *cltHandlePtr;
  1805.     register Fspdev_ServerIOHandle    *pdevHandlePtr;
  1806.  
  1807.     cltHandlePtr = Fsutil_HandleFetchType(Fspdev_ClientIOHandle, fileIDPtr);
  1808.     if (cltHandlePtr == (Fspdev_ClientIOHandle *)NIL) {
  1809.     printf( "FspdevPseudoStreamGetIOAttr, no %s handle <%d,%x,%x> client %d\n",
  1810.         Fsutil_FileTypeToString(fileIDPtr->type), fileIDPtr->serverID,
  1811.         fileIDPtr->major, fileIDPtr->minor, clientID);
  1812.     return(FS_FILE_NOT_FOUND);
  1813.     }
  1814.     Fsutil_HandleRelease(cltHandlePtr, TRUE);
  1815.     pdevHandlePtr = cltHandlePtr->pdevHandlePtr;
  1816.     LOCK_MONITOR;
  1817.  
  1818.     attrPtr->accessTime.seconds = pdevHandlePtr->ctrlHandlePtr->accessTime;
  1819.     attrPtr->dataModifyTime.seconds = pdevHandlePtr->ctrlHandlePtr->modifyTime;
  1820.  
  1821.     UNLOCK_MONITOR;
  1822.     return(SUCCESS);
  1823. }
  1824.  
  1825. /*
  1826.  *----------------------------------------------------------------------
  1827.  *
  1828.  * FspdevPseudoStreamSetIOAttr --
  1829.  *
  1830.  *    Set the IO attributes of a pseudo-device.
  1831.  *
  1832.  * Results:
  1833.  *    An error code.
  1834.  *
  1835.  * Side effects:
  1836.  *    Updates the access and modify times kept in the pdev state.
  1837.  *
  1838.  *----------------------------------------------------------------------
  1839.  */
  1840. ReturnStatus
  1841. FspdevPseudoStreamSetIOAttr(fileIDPtr, attrPtr, flags)
  1842.     register Fs_FileID        *fileIDPtr;    /* Identfies pdev connection */
  1843.     register Fs_Attributes    *attrPtr;    /* Return - the attributes */
  1844.     int                flags;        /* Tells which attrs to set */
  1845. {
  1846.     Fspdev_ClientIOHandle        *cltHandlePtr;
  1847.     register Fspdev_ServerIOHandle    *pdevHandlePtr;
  1848.  
  1849.     cltHandlePtr = Fsutil_HandleFetchType(Fspdev_ClientIOHandle, fileIDPtr);
  1850.     if (cltHandlePtr == (Fspdev_ClientIOHandle *)NIL) {
  1851.     printf( "FspdevPseudoStreamSetIOAttr, no handle <%d,%d,%x,%x>\n",
  1852.         fileIDPtr->serverID, fileIDPtr->type,
  1853.         fileIDPtr->major, fileIDPtr->minor);
  1854.     return(FS_FILE_NOT_FOUND);
  1855.     }
  1856.     Fsutil_HandleRelease(cltHandlePtr, TRUE);
  1857.     pdevHandlePtr = cltHandlePtr->pdevHandlePtr;
  1858.     LOCK_MONITOR;
  1859.     if (flags & FS_SET_TIMES) {
  1860.     pdevHandlePtr->ctrlHandlePtr->accessTime = attrPtr->accessTime.seconds;
  1861.     pdevHandlePtr->ctrlHandlePtr->modifyTime = attrPtr->dataModifyTime.seconds;
  1862.     }
  1863.     UNLOCK_MONITOR;
  1864.     return(SUCCESS);
  1865. }
  1866.  
  1867. /*
  1868.  *----------------------------------------------------------------------
  1869.  *
  1870.  * FspdevPseudoStreamRead --
  1871.  *
  1872.  *    Read from a pseudo-device stream. If there is data in the read
  1873.  *    ahead buffer (if one exists), that is used to satisfy the read.
  1874.  *    Otherwise a request-response exchange with the server is used
  1875.  *    to do the read.
  1876.  *
  1877.  * Results:
  1878.  *    SUCCESS, and *lenPtr reflects how much was read.  When the server
  1879.  *    goes away EOF is simulated by a SUCCESS return and *lenPtr == 0.
  1880.  *    If there is no data in the read ahead buffer FS_WOULD_BLOCK is returned.
  1881.  *
  1882.  * Side effects:
  1883.  *    If applicable, pointers into the read ahead buffer are adjusted.
  1884.  *    The buffer is filled with the number of bytes indicated by
  1885.  *    the length parameter.  The in/out length parameter specifies
  1886.  *    the buffer size on input and is updated to reflect the number
  1887.  *    of bytes actually read.
  1888.  *
  1889.  *----------------------------------------------------------------------
  1890.  */
  1891.  
  1892. ReturnStatus
  1893. FspdevPseudoStreamRead(streamPtr, readPtr, waitPtr, replyPtr)
  1894.     register Fs_Stream     *streamPtr;    /* Stream to read from. */
  1895.     Fs_IOParam        *readPtr;    /* Read parameter block. */
  1896.     Sync_RemoteWaiter    *waitPtr;    /* Process info for remote waiting */
  1897.     Fs_IOReply        *replyPtr;    /* Signal to return, if any,
  1898.                      * plus the amount read. */
  1899. {
  1900.     ReturnStatus     status;
  1901.     register Fspdev_ClientIOHandle *cltHandlePtr =
  1902.         (Fspdev_ClientIOHandle *)streamPtr->ioHandlePtr;
  1903.     register Fspdev_ServerIOHandle *pdevHandlePtr = cltHandlePtr->pdevHandlePtr;
  1904.     Pdev_Request    request;
  1905.  
  1906.     LOCK_MONITOR;
  1907.     while (pdevHandlePtr->flags & PDEV_BUSY) {
  1908.     if ((pdevHandlePtr->flags & PDEV_SERVER_GONE) == 0) {
  1909.         (void)Sync_Wait(&pdevHandlePtr->access, FALSE);
  1910.     }
  1911.     if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  1912.         status = DEV_OFFLINE;
  1913.         goto exitNoServer;
  1914.     }
  1915.     }
  1916.     pdevHandlePtr->flags |= PDEV_BUSY;
  1917.  
  1918. #ifdef notdef
  1919.     {
  1920.     register Ioc_Owner *ownerPtr;
  1921.     /*
  1922.      * Check for access inside the owning process group.
  1923.      */
  1924.     ownerPtr = &pdevHandlePtr->ctrlHandlePtr->owner;
  1925.     if (((ownerPtr->procOrFamily == IOC_OWNER_FAMILY) &&
  1926.          (readPtr->familyID != ownerPtr->id)) ||
  1927.         ((ownerPtr->procOrFamily == IOC_OWNER_PROC) &&
  1928.          (readPtr->procID != ownerPtr->id))) {
  1929.         printf("PdevRead: ownership conflict\n");
  1930.         status = GEN_ABORTED_BY_SIGNAL;
  1931.         replyPtr->signal = SIG_TTY_INPUT;
  1932.         goto exit;
  1933.     }
  1934.     }
  1935. #endif
  1936.  
  1937.     if (pdevHandlePtr->readBuf.data != (Address)NIL) {
  1938.     /*
  1939.      * A read ahead buffer exists so we get data from it.  If it's
  1940.      * empty we put the client on the client I/O handle read wait list.
  1941.      */
  1942.     if (pdevHandlePtr->flags & PDEV_READ_BUF_EMPTY) {
  1943.         status = FS_WOULD_BLOCK;
  1944.         Fsutil_FastWaitListInsert(&pdevHandlePtr->cltReadWaitList, waitPtr);
  1945.         replyPtr->length = 0;
  1946.     } else {
  1947.         register int dataAvail, firstByte, lastByte, toRead;
  1948.         register Proc_ControlBlock *serverProcPtr;
  1949.  
  1950.         firstByte = pdevHandlePtr->readBuf.firstByte;
  1951.         lastByte = pdevHandlePtr->readBuf.lastByte;
  1952.         dataAvail = lastByte - firstByte + 1;
  1953.         if (dataAvail <= 0) {
  1954.         panic("FspdevPseudoStreamRead, dataAvail in read buf <= 0 bytes\n");
  1955.         status = DEV_OFFLINE;
  1956.         goto exit;
  1957.         }
  1958.         /*
  1959.          * Lock down the server process in preparation for copying
  1960.          * from the read ahead buffer.
  1961.          */
  1962.         serverProcPtr = Proc_LockPID(pdevHandlePtr->serverPID);
  1963.         if (serverProcPtr == (Proc_ControlBlock *)NIL) {
  1964.         status = DEV_OFFLINE;
  1965.         goto exit;
  1966.         }
  1967.         /*
  1968.          * Decide how much to read and note if we empty the buffer.
  1969.          */
  1970.         if (dataAvail > readPtr->length) {
  1971.         toRead = readPtr->length;
  1972.         } else {
  1973.         toRead = dataAvail;
  1974.         pdevHandlePtr->flags |= PDEV_READ_BUF_EMPTY;
  1975.         }
  1976.         DBG_PRINT( ("PDEV %x,%x Read %d Avail %d\n", 
  1977.             pdevHandlePtr->hdr.fileID.major,
  1978.             pdevHandlePtr->hdr.fileID.minor,
  1979.             toRead, dataAvail) );
  1980.         /*
  1981.          * Copy out of the read ahead buffer to the client's buffer.
  1982.          */
  1983.         status = Vm_CopyInProc(toRead, serverProcPtr,
  1984.               pdevHandlePtr->readBuf.data + firstByte,
  1985.               readPtr->buffer, (readPtr->flags & FS_USER) == 0);
  1986.         Proc_Unlock(serverProcPtr);
  1987.         /*
  1988.          * Update pointers and poke the server so it can find out.
  1989.          */
  1990.         replyPtr->length = toRead;
  1991.         pdevHandlePtr->readBuf.firstByte = firstByte + toRead;
  1992.         pdevHandlePtr->flags |= PDEV_READ_PTRS_CHANGED;
  1993.         Fsutil_FastWaitListNotify(&pdevHandlePtr->srvReadWaitList);
  1994.     }
  1995.     } else if (pdevHandlePtr->selectBits & FS_READABLE) {
  1996.     /*
  1997.      * No read ahead buffer and the state is readable.
  1998.      * Set up and do the request-response exchange.
  1999.      */
  2000.     request.hdr.operation        = PDEV_READ;
  2001.     request.param.read        = *readPtr;
  2002.  
  2003.     if (readPtr->flags & FS_USER) {
  2004.         pdevHandlePtr->flags |= FS_USER_OUT;
  2005.     }
  2006.     status = RequestResponse(pdevHandlePtr, sizeof(Pdev_Request),
  2007.         &request.hdr, 0, (Address) NIL, readPtr->length, readPtr->buffer,
  2008.             replyPtr, waitPtr);
  2009.     } else {
  2010.     /*
  2011.      * The pseudo-device is not readable now.
  2012.      */
  2013.     Fsutil_FastWaitListInsert(&pdevHandlePtr->cltReadWaitList, waitPtr);
  2014.     replyPtr->length = 0;
  2015.     status = FS_WOULD_BLOCK;
  2016.     }
  2017.     if (status == SUCCESS) {
  2018.     pdevHandlePtr->ctrlHandlePtr->accessTime = Fsutil_TimeInSeconds();
  2019.     }
  2020. exit:
  2021.     if (status == DEV_OFFLINE) {
  2022.     /*
  2023.      * Simulate EOF
  2024.      */
  2025.     status = SUCCESS;
  2026.     replyPtr->length = 0;
  2027.     }
  2028.     pdevHandlePtr->flags &= ~(PDEV_BUSY|FS_USER_OUT);
  2029. exitNoServer:
  2030.     Sync_Broadcast(&pdevHandlePtr->access);
  2031.     UNLOCK_MONITOR;
  2032.     return(status);
  2033. }
  2034.  
  2035. /*
  2036.  *----------------------------------------------------------------------
  2037.  *
  2038.  * FspdevPseudoStreamWrite --
  2039.  *
  2040.  *    Write to a pseudo-device by a client.  The write is done
  2041.  *    asynchronously if the stream allows that.  In that case we
  2042.  *    always say we could write as much as requested.  However, if
  2043.  *    the write is larger than the server's request buffer we
  2044.  *    break it into blocks that each fit. To support UDP, the
  2045.  *    stream can also be marked to dis-allow these large writes.
  2046.  *    Finally, the stream may be marked synchronous in which case
  2047.  *    we tell RequestResponse to wait for a reply.
  2048.  *
  2049.  * Results:
  2050.  *    SUCCESS            - the data was written.
  2051.  *
  2052.  * Side effects:
  2053.  *    The data in the buffer is written to the device.  Large writes
  2054.  *    are broken into a series of shorter writes, although we keep
  2055.  *    the access lock on the pseudo-stream so the whole write completes.
  2056.  *    The in/out length parameter specifies the amount of data to write
  2057.  *    and is updated to reflect the number of bytes actually written.
  2058.  *
  2059.  *----------------------------------------------------------------------
  2060.  */
  2061. ENTRY ReturnStatus
  2062. FspdevPseudoStreamWrite(streamPtr, writePtr, waitPtr, replyPtr)
  2063.     Fs_Stream     *streamPtr;    /* Stream to write to. */
  2064.     Fs_IOParam        *writePtr;    /* Read parameter block */
  2065.     Sync_RemoteWaiter    *waitPtr;    /* Process info for remote waiting */
  2066.     Fs_IOReply        *replyPtr;    /* Signal to return, if any */
  2067. {
  2068.     register Fspdev_ClientIOHandle *cltHandlePtr =
  2069.         (Fspdev_ClientIOHandle *)streamPtr->ioHandlePtr;
  2070.     register Fspdev_ServerIOHandle *pdevHandlePtr = cltHandlePtr->pdevHandlePtr;
  2071.     ReturnStatus     status = SUCCESS;
  2072.     Pdev_Request    request;
  2073.     int            amountWritten;
  2074.     int            numBytes;
  2075.     int            maxRequestSize;
  2076.     int            totalToWrite;
  2077.  
  2078.     LOCK_MONITOR;
  2079.     /*
  2080.      * Wait for exclusive access to the stream.
  2081.      */
  2082.     while (pdevHandlePtr->flags & PDEV_BUSY) {
  2083.     if ((pdevHandlePtr->flags & PDEV_SERVER_GONE) == 0) {
  2084.         (void)Sync_Wait(&pdevHandlePtr->access, FALSE);
  2085.     }
  2086.     if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  2087.         status = FS_BROKEN_PIPE;
  2088.         goto exitNoServer;
  2089.     }
  2090.     }
  2091.     pdevHandlePtr->flags |= PDEV_BUSY;
  2092.     if (writePtr->flags & FS_USER) {
  2093.     pdevHandlePtr->flags |= FS_USER_IN;
  2094.     }
  2095.  
  2096. #ifdef notdef
  2097.     {
  2098.     /*
  2099.      * Check for access inside the owning process group.
  2100.      * (This doesn't work presently, 6/89.  We'll rely on
  2101.      * the tty driver to do this checking for us.)
  2102.      *
  2103.      * Getting 4.3 BSD semantics is tricky because the operation is
  2104.      * supposed to succeed if the TTYOUT signal is blocked. Need a
  2105.      * flag passed down from Fs_Write.
  2106.      */
  2107.     Ioc_Owner        *ownerPtr;
  2108.     ownerPtr = &pdevHandlePtr->ctrlHandlePtr->owner;
  2109.     if (((ownerPtr->procOrFamily == IOC_OWNER_FAMILY) &&
  2110.          (writePtr->familyID != ownerPtr->id)) ||
  2111.         ((ownerPtr->procOrFamily == IOC_OWNER_PROC) &&
  2112.          (writePtr->procID != ownerPtr->id))) {
  2113.         printf("PdevWrite: ownership conflict\n");
  2114.         status = GEN_ABORTED_BY_SIGNAL;
  2115.         replyPtr->signal = SIG_TTY_OUTPUT;
  2116.         goto exit;
  2117.     }
  2118.     }
  2119. #endif
  2120.     /*
  2121.      * Allow flow control by checking the select bits and only trying
  2122.      * the operation if the state allows it.
  2123.      */
  2124.     if ((pdevHandlePtr->selectBits & FS_WRITABLE) == 0) {
  2125.     replyPtr->length = 0;
  2126.     Fsutil_FastWaitListInsert(&pdevHandlePtr->cltWriteWaitList, waitPtr);
  2127.     status = FS_WOULD_BLOCK;
  2128.     goto exit;
  2129.     }
  2130.  
  2131.     maxRequestSize = pdevHandlePtr->requestBuf.size - sizeof(Pdev_Request);
  2132.     if (writePtr->length > maxRequestSize &&
  2133.     (pdevHandlePtr->flags & PDEV_NO_BIG_WRITES)) {
  2134.     printf("Too large a write (%d bytes) an a (UDP?) pseudo-device\n",
  2135.         writePtr->length);
  2136.     status = GEN_INVALID_ARG;
  2137.     goto exit;
  2138.     }
  2139.  
  2140.     if (pdevHandlePtr->flags & PDEV_WRITE_BEHIND) {
  2141.     request.hdr.operation        = PDEV_WRITE_ASYNC;
  2142.     } else {
  2143.     request.hdr.operation        = PDEV_WRITE;
  2144.     }
  2145.     request.param.write            = *writePtr;
  2146.     request.param.write.buffer        = 0;
  2147.  
  2148.     amountWritten = 0;
  2149.     totalToWrite = writePtr->length;
  2150.     while ((writePtr->length > 0) && (status == SUCCESS)) {
  2151.     /*
  2152.      * Loop to put the maximum amount of data into the request
  2153.      * buffer until the whole block has been transferred.  The
  2154.      * server returns an int, the number of bytes it accepted.
  2155.      */
  2156.     request.param.write.length = (writePtr->length > maxRequestSize) ?
  2157.                       maxRequestSize : writePtr->length;
  2158.     request.param.write.offset = writePtr->offset + amountWritten;
  2159.     status = RequestResponse(pdevHandlePtr, sizeof(Pdev_Request),
  2160.                  &request.hdr, request.param.write.length,
  2161.                  writePtr->buffer + amountWritten,
  2162.                  sizeof(int), (Address)&numBytes,
  2163.                  replyPtr, waitPtr);
  2164.     if (pdevHandlePtr->flags & PDEV_WRITE_BEHIND) {
  2165.         /*
  2166.          * Assume all bytes accepted when write-behind is enabled.
  2167.          */
  2168.         numBytes = request.param.write.length;
  2169.     } else if (replyPtr->length != sizeof(int)) {
  2170.         numBytes = 0;
  2171.     }
  2172.     amountWritten += numBytes;
  2173.     writePtr->length -= numBytes;
  2174.     }
  2175.     if (amountWritten > totalToWrite) {
  2176.     printf("FspdevPseudoStreamWrite: \"%s\" amount written (%d) > requested (%d)\n",
  2177.         Fsutil_HandleName(streamPtr->ioHandlePtr), amountWritten, totalToWrite);
  2178.     amountWritten = totalToWrite;
  2179.     }
  2180.     replyPtr->length = amountWritten;
  2181.     if (amountWritten > 0) {
  2182.     pdevHandlePtr->ctrlHandlePtr->modifyTime = Fsutil_TimeInSeconds();
  2183.     }
  2184. exit:
  2185.     if (status == DEV_OFFLINE) {
  2186.     /*
  2187.      * Simulate a broken pipe so writers die.
  2188.      */
  2189.     replyPtr->signal = SIG_PIPE;
  2190.     status = FS_BROKEN_PIPE;
  2191.     }
  2192.     if (replyPtr->signal != 0) {
  2193.     printf("PdevWrite: signal %d\n", replyPtr->signal);
  2194.     }
  2195.     pdevHandlePtr->flags &= ~(PDEV_BUSY|FS_USER_IN);
  2196. exitNoServer:
  2197.     Sync_Broadcast(&pdevHandlePtr->access);
  2198.     UNLOCK_MONITOR;
  2199.     return(status);
  2200. }
  2201.  
  2202. /*
  2203.  *----------------------------------------------------------------------
  2204.  *
  2205.  * FspdevPseudoStreamIOControl --
  2206.  *
  2207.  *    IOControls for pseudo-device.  The in parameter block of the
  2208.  *    IOControl is passed to the server, and its response is used
  2209.  *    to fill the return parameter block of the client.
  2210.  *
  2211.  * Results:
  2212.  *    SUCCESS            - the operation was successful.
  2213.  *
  2214.  * Side effects:
  2215.  *    None here in the kernel, anyway.
  2216.  *
  2217.  *----------------------------------------------------------------------
  2218.  */
  2219.  
  2220. ReturnStatus
  2221. FspdevPseudoStreamIOControl(streamPtr, ioctlPtr, replyPtr)
  2222.     Fs_Stream    *streamPtr;    /* Stream to pseudo-device */
  2223.     Fs_IOCParam *ioctlPtr;    /* Standard I/O Control parameter block */
  2224.     Fs_IOReply *replyPtr;    /* Output buffer length and signal to return */
  2225. {
  2226.     ReturnStatus     status;
  2227.     Pdev_Request    request;
  2228.     register Fspdev_ClientIOHandle *cltHandlePtr =
  2229.         (Fspdev_ClientIOHandle *)streamPtr->ioHandlePtr;
  2230.     register Fspdev_ServerIOHandle *pdevHandlePtr = cltHandlePtr->pdevHandlePtr;
  2231.     Boolean    sendToServer;
  2232.  
  2233.     LOCK_MONITOR;
  2234.     /*
  2235.      * Wait for exclusive access to the stream.
  2236.      */
  2237.     while (pdevHandlePtr->flags & PDEV_BUSY) {
  2238.     if ((pdevHandlePtr->flags & PDEV_SERVER_GONE) == 0) {
  2239.         (void)Sync_Wait(&pdevHandlePtr->access, FALSE);
  2240.     }
  2241.     if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  2242.         status = DEV_OFFLINE;
  2243.         goto exit;
  2244.     }
  2245.     }
  2246.     pdevHandlePtr->flags |= PDEV_BUSY;
  2247.  
  2248.     /*
  2249.      * Decide if the buffers are already in the kernel or not.  The buffers
  2250.      * for generic I/O controls are copied in, and if we are being called
  2251.      * from an RPC stub they are also in kernel space.
  2252.      */
  2253.     if (ioctlPtr->flags & FS_USER_IN) {
  2254.     pdevHandlePtr->flags |= FS_USER_IN;
  2255.     }
  2256.     if (ioctlPtr->flags & FS_USER_OUT) {
  2257.     pdevHandlePtr->flags |= FS_USER_OUT;
  2258.     }
  2259.  
  2260.     status = SUCCESS;
  2261.     sendToServer = TRUE;
  2262.  
  2263.     if (ioctlPtr->command == IOC_NUM_READABLE &&
  2264.     pdevHandlePtr->readBuf.data != (Address)NIL) {
  2265.     /*
  2266.      * Trap out the IOC_NUM_READABLE if there's a read ahead buf.
  2267.      */
  2268.     int bytesAvail;
  2269.     if (pdevHandlePtr->flags & PDEV_READ_BUF_EMPTY) {
  2270.         bytesAvail = 0;
  2271.     } else {
  2272.         bytesAvail = pdevHandlePtr->readBuf.lastByte -
  2273.              pdevHandlePtr->readBuf.firstByte + 1;
  2274.     }
  2275.     if (ioctlPtr->outBufSize != sizeof(int)) {
  2276.         status = GEN_INVALID_ARG;
  2277.     } else if (ioctlPtr->format != mach_Format) {
  2278.         int size = sizeof(int);
  2279.         int inSize = sizeof(int);
  2280.         int fmtStatus;
  2281.         fmtStatus = Fmt_Convert("w", mach_Format, &inSize, 
  2282.                 (Address) &bytesAvail,
  2283.                 ioctlPtr->format, &size, ioctlPtr->outBuffer);
  2284.         if (fmtStatus != 0) {
  2285.         printf("Format of ioctl failed <0x%x>\n", fmtStatus);
  2286.         status = GEN_INVALID_ARG;
  2287.         }
  2288.         if (size != sizeof(int)) {
  2289.         status = GEN_INVALID_ARG;
  2290.         }
  2291.     } else {
  2292.         *(int *)ioctlPtr->outBuffer = bytesAvail;
  2293.     }
  2294.     DBG_PRINT( ("IOC  %x,%x num readable %d\n",
  2295.         pdevHandlePtr->hdr.fileID.major,
  2296.         pdevHandlePtr->hdr.fileID.minor,
  2297.         bytesAvail) );
  2298.     } else {
  2299.     /*
  2300.      * Switch out on command for any special processing,
  2301.      * then do a request-response transaction with the server.
  2302.      */
  2303.     switch(ioctlPtr->command) {
  2304.         case IOC_SET_OWNER: {
  2305.         /*
  2306.          * Siphon off the ownership so we can enforce it in the kernel.
  2307.          */
  2308.         if (ioctlPtr->inBufSize < sizeof(Ioc_Owner)) {
  2309.             status = GEN_INVALID_ARG;
  2310.         } else {
  2311.             pdevHandlePtr->ctrlHandlePtr->owner =
  2312.                 *(Ioc_Owner *)ioctlPtr->inBuffer;
  2313.         }
  2314.         break;
  2315.         }
  2316.         case IOC_GET_OWNER: {
  2317.         /*
  2318.          * Do our own get owner, but let the server see the request.
  2319.          */
  2320.         if (ioctlPtr->outBufSize < sizeof(Ioc_Owner)) {
  2321.             status = GEN_INVALID_ARG;
  2322.         } else {
  2323.             *(Ioc_Owner *)ioctlPtr->outBuffer =
  2324.                 pdevHandlePtr->ctrlHandlePtr->owner;
  2325.         }
  2326.         break;
  2327.         }
  2328.         case IOC_PREFIX: 
  2329.         status = SUCCESS;
  2330.         sendToServer = FALSE;
  2331.         break;
  2332.     }
  2333.     if (status == SUCCESS && sendToServer) {
  2334.         request.hdr.operation    = PDEV_IOCTL;
  2335.         request.param.ioctl        = *ioctlPtr;
  2336.  
  2337.         status = RequestResponse(pdevHandlePtr, sizeof(Pdev_Request),
  2338.                  &request.hdr,
  2339.                  ioctlPtr->inBufSize, ioctlPtr->inBuffer,
  2340.                  ioctlPtr->outBufSize, ioctlPtr->outBuffer,
  2341.                  replyPtr, (Sync_RemoteWaiter *)NIL);
  2342.     }
  2343.     }
  2344.  
  2345.     pdevHandlePtr->flags &= ~(PDEV_BUSY|FS_USER_IN|FS_USER_OUT);
  2346. exit:
  2347.     Sync_Broadcast(&pdevHandlePtr->access);
  2348.     UNLOCK_MONITOR;
  2349.     return(status);
  2350. }
  2351.  
  2352.  
  2353. /*
  2354.  *----------------------------------------------------------------------
  2355.  *
  2356.  * FspdevPseudoStreamSelect --
  2357.  *
  2358.  *    Select on a pseudo-device.  This is done by checking the stream
  2359.  *    state kept on the host of the server.  If the pseudo device isn't
  2360.  *    selectable we just return and let the server's IOC_PDEV_READY
  2361.  *    IOControl do the wakeup for us. (ie. we don't use the handle wait
  2362.  *    lists.)
  2363.  *
  2364.  * Results:
  2365.  *    SUCCESS    or FS_WOULD_BLOCK
  2366.  *
  2367.  * Side effects:
  2368.  *    *outFlagsPtr modified to indicate whether the device is
  2369.  *    readable or writable.
  2370.  *
  2371.  *----------------------------------------------------------------------
  2372.  */
  2373.  
  2374. ReturnStatus
  2375. FspdevPseudoStreamSelect(hdrPtr, waitPtr, readPtr, writePtr, exceptPtr)
  2376.     Fs_HandleHeader    *hdrPtr;    /* Handle on pdev to select */
  2377.     Sync_RemoteWaiter    *waitPtr;    /* Process info for remote waiting */
  2378.     int         *readPtr;    /* Bit to clear if non-readable */
  2379.     int         *writePtr;    /* Bit to clear if non-writeable */
  2380.     int         *exceptPtr;    /* Bit to clear if non-exceptable */
  2381. {
  2382.     ReturnStatus status;
  2383.     register Fspdev_ClientIOHandle *cltHandlePtr = (Fspdev_ClientIOHandle *)hdrPtr;
  2384.     register Fspdev_ServerIOHandle *pdevHandlePtr = cltHandlePtr->pdevHandlePtr;
  2385.  
  2386.     LOCK_MONITOR;
  2387.  
  2388.     PDEV_TSELECT(&cltHandlePtr->hdr.fileID, *readPtr, *writePtr, *exceptPtr);
  2389.  
  2390.     if ((pdevHandlePtr->flags & PDEV_SERVER_GONE) ||
  2391.     (pdevHandlePtr->flags & PDEV_SETUP) == 0) {
  2392.     status = DEV_OFFLINE;
  2393.     } else {
  2394.     if (*readPtr) {
  2395.         if (((pdevHandlePtr->readBuf.data == (Address)NIL) &&
  2396.          ((pdevHandlePtr->selectBits & FS_READABLE) == 0)) ||
  2397.         ((pdevHandlePtr->readBuf.data != (Address)NIL) &&
  2398.          (pdevHandlePtr->flags & PDEV_READ_BUF_EMPTY))) {
  2399.         *readPtr = 0;
  2400.         if (waitPtr != (Sync_RemoteWaiter *)NIL) {
  2401.             Fsutil_FastWaitListInsert(&pdevHandlePtr->cltReadWaitList,
  2402.                     waitPtr);
  2403.         }
  2404.         }
  2405.     }
  2406.     if (*writePtr && ((pdevHandlePtr->selectBits & FS_WRITABLE) == 0)) {
  2407.         *writePtr = 0;
  2408.         if (waitPtr != (Sync_RemoteWaiter *)NIL) {
  2409.         Fsutil_FastWaitListInsert(&pdevHandlePtr->cltWriteWaitList, waitPtr);
  2410.         }
  2411.     }    
  2412.     if (*exceptPtr && ((pdevHandlePtr->selectBits & FS_EXCEPTION) == 0)) {
  2413.             *exceptPtr = 0;
  2414.         if (waitPtr != (Sync_RemoteWaiter *)NIL) {
  2415.         Fsutil_FastWaitListInsert(&pdevHandlePtr->cltExceptWaitList,waitPtr);
  2416.         }
  2417.     }
  2418.     status = SUCCESS;
  2419.     }
  2420.     UNLOCK_MONITOR;
  2421.     return(status);
  2422. }
  2423.  
  2424.  
  2425. /*
  2426.  *----------------------------------------------------------------------
  2427.  *
  2428.  * PdevClientNotify --
  2429.  *
  2430.  *    Wakeup any processes selecting or blocking on the pseudo-stream.
  2431.  *
  2432.  * Results:
  2433.  *    None.
  2434.  *
  2435.  * Side effects:
  2436.  *    None.
  2437.  *
  2438.  *----------------------------------------------------------------------
  2439.  */
  2440.  
  2441. INTERNAL static void
  2442. PdevClientNotify(pdevHandlePtr)
  2443.     Fspdev_ServerIOHandle *pdevHandlePtr;
  2444. {
  2445.     register int selectBits = pdevHandlePtr->selectBits;
  2446.  
  2447.     PDEV_WAKEUP(&pdevHandlePtr->hdr.fileID, pdevHandlePtr->clientPID,
  2448.         pdevHandlePtr->selectBits);
  2449.     if (selectBits & FS_READABLE) {
  2450.     Fsutil_FastWaitListNotify(&pdevHandlePtr->cltReadWaitList);
  2451.     }
  2452.     if (selectBits & FS_WRITABLE) {
  2453.     Fsutil_FastWaitListNotify(&pdevHandlePtr->cltWriteWaitList);
  2454.     }
  2455.     if (selectBits & FS_EXCEPTION) {
  2456.     Fsutil_FastWaitListNotify(&pdevHandlePtr->cltExceptWaitList);
  2457.     }
  2458. }
  2459.  
  2460. /*
  2461.  *----------------------------------------------------------------------
  2462.  *
  2463.  * FspdevPseudoStreamCloseInt --
  2464.  *
  2465.  *    Do a close request-response with the server.
  2466.  *
  2467.  * Results:
  2468.  *    None.
  2469.  *
  2470.  * Side effects:
  2471.  *    None.
  2472.  *
  2473.  *----------------------------------------------------------------------
  2474.  */
  2475.  
  2476. ENTRY void
  2477. FspdevPseudoStreamCloseInt(pdevHandlePtr)
  2478.     register Fspdev_ServerIOHandle *pdevHandlePtr;
  2479. {
  2480.     Pdev_Request    request;
  2481.  
  2482.     LOCK_MONITOR;
  2483.  
  2484.     while (pdevHandlePtr->flags & PDEV_BUSY) {
  2485.     if ((pdevHandlePtr->flags & PDEV_SERVER_GONE) == 0) {
  2486.         (void)Sync_Wait(&pdevHandlePtr->access, FALSE);
  2487.     }
  2488.     if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  2489.         goto exit;
  2490.     }
  2491.     }
  2492.     pdevHandlePtr->flags |= PDEV_BUSY;
  2493.     /*
  2494.      * Someday we could set up a timeout call-back here in case
  2495.      * the server never replies.
  2496.      */
  2497.     request.hdr.operation = PDEV_CLOSE;
  2498.     (void) RequestResponse(pdevHandlePtr, sizeof(Pdev_Request), &request.hdr,
  2499.             0, (Address)NIL, 0, (Address)NIL, (Fs_IOReply *) NIL,
  2500.             (Sync_RemoteWaiter *)NIL);
  2501.     pdevHandlePtr->flags &= ~(PDEV_BUSY|FS_USER);
  2502. exit:
  2503.     Sync_LockClear(&pdevHandlePtr->lock);
  2504.     Sync_Broadcast(&pdevHandlePtr->access);
  2505.     UNLOCK_MONITOR;
  2506. }
  2507.